| /* | |
| * DirectDraw DGA2 interface | |
| * | |
| * Copyright 2001 TransGaming Technologies, Inc. | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| */ | |
| #include "config.h" | |
| #ifdef HAVE_LIBXXF86DGA2 | |
| #define NONAMELESSUNION | |
| #define NONAMELESSSTRUCT | |
| #include <X11/Xlib.h> | |
| #include <X11/extensions/xf86dga.h> | |
| #include "x11drv.h" | |
| #include "x11ddraw.h" | |
| #include "dga2.h" | |
| #include "windef.h" | |
| #include "wingdi.h" | |
| #include "ddrawi.h" | |
| #include "wine/debug.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(x11drv); | |
| extern int usedga; | |
| LPDDHALMODEINFO xf86dga2_modes; | |
| unsigned xf86dga2_mode_count; | |
| HWND DGAhwnd = 0; | |
| static XDGAMode* modes; | |
| static void convert_mode(XDGAMode *mode, LPDDHALMODEINFO info) | |
| { | |
| info->dwWidth = mode->viewportWidth; | |
| info->dwHeight = mode->viewportHeight; | |
| info->wRefreshRate = mode->verticalRefresh; | |
| info->lPitch = mode->bytesPerScanline; | |
| info->dwBPP = (mode->depth < 24) ? mode->depth : mode->bitsPerPixel; | |
| info->wFlags = (mode->depth == 8) ? DDMODEINFO_PALETTIZED : 0; | |
| info->dwRBitMask = mode->redMask; | |
| info->dwGBitMask = mode->greenMask; | |
| info->dwBBitMask = mode->blueMask; | |
| info->dwAlphaBitMask = 0; | |
| TRACE(" width=%ld, height=%ld, bpp=%ld, refresh=%d\n", | |
| info->dwWidth, info->dwHeight, info->dwBPP, info->wRefreshRate); | |
| } | |
| static int DGA2ErrorHandler(Display *dpy, XErrorEvent *event, void *arg) | |
| { | |
| return 1; | |
| } | |
| static void X11DRV_DGAKeyPressEvent( HWND hwnd, XEvent *xev ) | |
| { | |
| /* Fill a XKeyEvent to send to EVENT_Key */ | |
| XDGAKeyEvent *event = (XDGAKeyEvent *)xev; | |
| XEvent ke; | |
| ke.xkey.type = KeyPress; | |
| ke.xkey.serial = event->serial; | |
| ke.xkey.send_event = FALSE; | |
| ke.xkey.display = event->display; | |
| ke.xkey.window = 0; | |
| ke.xkey.root = 0; | |
| ke.xkey.subwindow = 0; | |
| ke.xkey.time = event->time; | |
| ke.xkey.x = -1; | |
| ke.xkey.y = -1; | |
| ke.xkey.x_root = -1; | |
| ke.xkey.y_root = -1; | |
| ke.xkey.state = event->state; | |
| ke.xkey.keycode = event->keycode; | |
| ke.xkey.same_screen = TRUE; | |
| X11DRV_KeyEvent( 0, &ke ); | |
| } | |
| static void X11DRV_DGAKeyReleaseEvent( HWND hwnd, XEvent *xev ) | |
| { | |
| /* Fill a XKeyEvent to send to EVENT_Key */ | |
| XDGAKeyEvent *event = (XDGAKeyEvent *)xev; | |
| XEvent ke; | |
| ke.xkey.type = KeyRelease; | |
| ke.xkey.serial = event->serial; | |
| ke.xkey.send_event = FALSE; | |
| ke.xkey.display = event->display; | |
| ke.xkey.window = 0; | |
| ke.xkey.root = 0; | |
| ke.xkey.subwindow = 0; | |
| ke.xkey.time = event->time; | |
| ke.xkey.x = -1; | |
| ke.xkey.y = -1; | |
| ke.xkey.x_root = -1; | |
| ke.xkey.y_root = -1; | |
| ke.xkey.state = event->state; | |
| ke.xkey.keycode = event->keycode; | |
| ke.xkey.same_screen = TRUE; | |
| X11DRV_KeyEvent( 0, &ke ); | |
| } | |
| void X11DRV_XF86DGA2_Init(void) | |
| { | |
| int nmodes, major, minor, i, event_base, error_base; | |
| Bool ok; | |
| TRACE("\n"); | |
| if (xf86dga2_modes) return; /* already initialized? */ | |
| /* if in desktop mode, don't use DGA */ | |
| if (root_window != DefaultRootWindow(gdi_display)) return; | |
| if (!usedga) return; | |
| wine_tsx11_lock(); | |
| ok = XDGAQueryExtension(gdi_display, &event_base, &error_base); | |
| if (ok) | |
| { | |
| X11DRV_expect_error(gdi_display, DGA2ErrorHandler, NULL); | |
| ok = XDGAQueryVersion(gdi_display, &major, &minor); | |
| if (X11DRV_check_error()) ok = FALSE; | |
| } | |
| wine_tsx11_unlock(); | |
| if (!ok) return; | |
| if (major < 2) return; /* only bother with DGA 2+ */ | |
| /* test that it works */ | |
| wine_tsx11_lock(); | |
| X11DRV_expect_error(gdi_display, DGA2ErrorHandler, NULL); | |
| ok = XDGAOpenFramebuffer(gdi_display, DefaultScreen(gdi_display)); | |
| if (X11DRV_check_error()) ok = FALSE; | |
| if (ok) | |
| { | |
| XDGACloseFramebuffer(gdi_display, DefaultScreen(gdi_display)); | |
| /* retrieve modes */ | |
| modes = XDGAQueryModes(gdi_display, DefaultScreen(gdi_display), &nmodes); | |
| if (!modes) ok = FALSE; | |
| } | |
| else WARN("disabling XF86DGA2 (insufficient permissions?)\n"); | |
| wine_tsx11_unlock(); | |
| if (!ok) return; | |
| TRACE("DGA modes: count=%d\n", nmodes); | |
| xf86dga2_mode_count = nmodes+1; | |
| xf86dga2_modes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DDHALMODEINFO) * (nmodes+1)); | |
| /* make dummy mode for exiting DGA */ | |
| memset(&xf86dga2_modes[0], 0, sizeof(xf86dga2_modes[0])); | |
| /* convert modes to DDHALMODEINFO format */ | |
| for (i=0; i<nmodes; i++) | |
| convert_mode(&modes[i], &xf86dga2_modes[i+1]); | |
| /* register event handlers */ | |
| X11DRV_register_event_handler( event_base + MotionNotify, X11DRV_DGAMotionEvent ); | |
| X11DRV_register_event_handler( event_base + ButtonPress, X11DRV_DGAButtonPressEvent ); | |
| X11DRV_register_event_handler( event_base + ButtonRelease, X11DRV_DGAButtonReleaseEvent ); | |
| X11DRV_register_event_handler( event_base + KeyPress, X11DRV_DGAKeyPressEvent ); | |
| X11DRV_register_event_handler( event_base + KeyRelease, X11DRV_DGAKeyReleaseEvent ); | |
| TRACE("Enabling XF86DGA2 mode\n"); | |
| } | |
| void X11DRV_XF86DGA2_Cleanup(void) | |
| { | |
| wine_tsx11_lock(); | |
| if (modes) XFree(modes); | |
| wine_tsx11_unlock(); | |
| } | |
| static XDGADevice *dga_dev; | |
| static VIDMEM dga_mem = { | |
| VIDMEM_ISRECTANGULAR | VIDMEM_ISHEAP | |
| }; | |
| static DWORD PASCAL X11DRV_XF86DGA2_SetMode(LPDDHAL_SETMODEDATA data) | |
| { | |
| LPDDRAWI_DIRECTDRAW_LCL ddlocal = data->lpDD->lpExclusiveOwner; | |
| DWORD vram; | |
| Display *display = gdi_display; | |
| data->ddRVal = DD_OK; | |
| wine_tsx11_lock(); | |
| if (data->dwModeIndex) { | |
| /* enter DGA */ | |
| XDGADevice *new_dev = NULL; | |
| if (dga_dev || XDGAOpenFramebuffer(display, DefaultScreen(display))) | |
| new_dev = XDGASetMode(display, DefaultScreen(display), modes[data->dwModeIndex-1].num); | |
| if (new_dev) { | |
| XDGASetViewport(display, DefaultScreen(display), 0, 0, XDGAFlipImmediate); | |
| if (dga_dev) { | |
| VirtualFree(dga_dev->data, 0, MEM_RELEASE); | |
| XFree(dga_dev); | |
| } else { | |
| XDGASelectInput(display, DefaultScreen(display), | |
| KeyPressMask|KeyReleaseMask| | |
| ButtonPressMask|ButtonReleaseMask| | |
| PointerMotionMask); | |
| DGAhwnd = (HWND)ddlocal->hWnd; | |
| } | |
| dga_dev = new_dev; | |
| vram = dga_dev->mode.bytesPerScanline * dga_dev->mode.imageHeight; | |
| VirtualAlloc(dga_dev->data, vram, MEM_SYSTEM, PAGE_READWRITE); | |
| dga_mem.fpStart = (FLATPTR)dga_dev->data; | |
| dga_mem.u1.dwWidth = dga_dev->mode.bytesPerScanline; | |
| dga_mem.u2.dwHeight = dga_dev->mode.imageHeight; | |
| X11DRV_DDHAL_SwitchMode(data->dwModeIndex, dga_dev->data, &dga_mem); | |
| X11DRV_DD_IsDirect = TRUE; | |
| } | |
| else { | |
| ERR("failed\n"); | |
| if (!dga_dev) XDGACloseFramebuffer(display, DefaultScreen(display)); | |
| data->ddRVal = DDERR_GENERIC; | |
| } | |
| } | |
| else if (dga_dev) { | |
| /* exit DGA */ | |
| X11DRV_DD_IsDirect = FALSE; | |
| X11DRV_DDHAL_SwitchMode(0, NULL, NULL); | |
| XDGASetMode(display, DefaultScreen(display), 0); | |
| VirtualFree(dga_dev->data, 0, MEM_RELEASE); | |
| DGAhwnd = 0; | |
| XFree(dga_dev); | |
| XDGACloseFramebuffer(display, DefaultScreen(display)); | |
| dga_dev = NULL; | |
| } | |
| wine_tsx11_unlock(); | |
| return DDHAL_DRIVER_HANDLED; | |
| } | |
| static LPDDHAL_CREATESURFACE X11DRV_XF86DGA2_old_create_surface; | |
| static DWORD PASCAL X11DRV_XF86DGA2_CreateSurface(LPDDHAL_CREATESURFACEDATA data) | |
| { | |
| LPDDRAWI_DDRAWSURFACE_LCL lcl = *data->lplpSList; | |
| LPDDRAWI_DDRAWSURFACE_GBL gbl = lcl->lpGbl; | |
| LPDDSURFACEDESC2 desc = (LPDDSURFACEDESC2)data->lpDDSurfaceDesc; | |
| HRESULT hr = DDHAL_DRIVER_NOTHANDLED; | |
| if (X11DRV_XF86DGA2_old_create_surface) | |
| hr = X11DRV_XF86DGA2_old_create_surface(data); | |
| if (desc->ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | DDSCAPS_BACKBUFFER)) { | |
| gbl->fpVidMem = 0; /* tell ddraw to allocate the memory */ | |
| hr = DDHAL_DRIVER_HANDLED; | |
| } | |
| return hr; | |
| } | |
| static DWORD PASCAL X11DRV_XF86DGA2_CreatePalette(LPDDHAL_CREATEPALETTEDATA data) | |
| { | |
| Display *display = gdi_display; | |
| wine_tsx11_lock(); | |
| data->lpDDPalette->u1.dwReserved1 = XDGACreateColormap(display, DefaultScreen(display), | |
| dga_dev, AllocAll); | |
| wine_tsx11_unlock(); | |
| if (data->lpColorTable) | |
| X11DRV_DDHAL_SetPalEntries(data->lpDDPalette->u1.dwReserved1, 0, 256, | |
| data->lpColorTable); | |
| data->ddRVal = DD_OK; | |
| return DDHAL_DRIVER_HANDLED; | |
| } | |
| static DWORD PASCAL X11DRV_XF86DGA2_Flip(LPDDHAL_FLIPDATA data) | |
| { | |
| Display *display = gdi_display; | |
| if (data->lpSurfCurr == X11DRV_DD_Primary) { | |
| DWORD ofs = data->lpSurfCurr->lpGbl->fpVidMem - dga_mem.fpStart; | |
| wine_tsx11_lock(); | |
| XDGASetViewport(display, DefaultScreen(display), | |
| (ofs % dga_dev->mode.bytesPerScanline)*8/dga_dev->mode.bitsPerPixel, | |
| ofs / dga_dev->mode.bytesPerScanline, | |
| XDGAFlipImmediate); | |
| wine_tsx11_unlock(); | |
| } | |
| data->ddRVal = DD_OK; | |
| return DDHAL_DRIVER_HANDLED; | |
| } | |
| static DWORD PASCAL X11DRV_XF86DGA2_SetPalette(LPDDHAL_SETPALETTEDATA data) | |
| { | |
| Display *display = gdi_display; | |
| if ((data->lpDDSurface == X11DRV_DD_Primary) && | |
| data->lpDDPalette && data->lpDDPalette->u1.dwReserved1) | |
| { | |
| wine_tsx11_lock(); | |
| XDGAInstallColormap(display, DefaultScreen(display), data->lpDDPalette->u1.dwReserved1); | |
| wine_tsx11_unlock(); | |
| } | |
| data->ddRVal = DD_OK; | |
| return DDHAL_DRIVER_HANDLED; | |
| } | |
| int X11DRV_XF86DGA2_CreateDriver(LPDDHALINFO info) | |
| { | |
| if (!xf86dga2_mode_count) return 0; /* no DGA */ | |
| info->dwNumModes = xf86dga2_mode_count; | |
| info->lpModeInfo = xf86dga2_modes; | |
| info->dwModeIndex = 0; | |
| X11DRV_XF86DGA2_old_create_surface = info->lpDDCallbacks->CreateSurface; | |
| info->lpDDCallbacks->SetMode = X11DRV_XF86DGA2_SetMode; | |
| info->lpDDCallbacks->CreateSurface = X11DRV_XF86DGA2_CreateSurface; | |
| info->lpDDCallbacks->CreatePalette = X11DRV_XF86DGA2_CreatePalette; | |
| info->lpDDSurfaceCallbacks->Flip = X11DRV_XF86DGA2_Flip; | |
| info->lpDDSurfaceCallbacks->SetPalette = X11DRV_XF86DGA2_SetPalette; | |
| return TRUE; | |
| } | |
| #endif /* HAVE_LIBXXF86DGA2 */ |