/* * 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 "ts_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; static XDGAMode* modes; static int dga_event, dga_error; 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; } void X11DRV_XF86DGA2_Init(void) { int nmodes, major, minor, i; 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, &dga_event, &dga_error); 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]); TRACE("Enabling XF86DGA2 mode\n"); } void X11DRV_XF86DGA2_Cleanup(void) { if (modes) TSXFree(modes); } 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); X11DRV_EVENT_SetDGAStatus((HWND)ddlocal->hWnd, dga_event); X11DRV_EVENT_SetInputMethod(X11DRV_INPUT_RELATIVE); } dga_dev = new_dev; vram = dga_dev->mode.bytesPerScanline * dga_dev->mode.imageHeight; VirtualAlloc(dga_dev->data, vram, MEM_RESERVE|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); X11DRV_EVENT_SetInputMethod(X11DRV_INPUT_ABSOLUTE); X11DRV_EVENT_SetDGAStatus(0, -1); 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 */