- Rename WIN_Handle16 to HWDN_16 and make it a macro.
[wine] / dlls / x11drv / dga2.c
1 /*
2  * DirectDraw DGA2 interface
3  *
4  * Copyright 2001 TransGaming Technologies, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #ifdef HAVE_LIBXXF86DGA2
24
25 #include "ts_xlib.h"
26 #include "ts_xf86dga2.h"
27 #include "x11drv.h"
28 #include "x11ddraw.h"
29 #include "dga2.h"
30
31 #include "windef.h"
32 #include "wingdi.h"
33 #include "ddrawi.h"
34 #include "wine/debug.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
37
38 extern int usedga;
39
40 LPDDHALMODEINFO xf86dga2_modes;
41 unsigned xf86dga2_mode_count;
42 static XDGAMode* modes;
43 static int dga_event, dga_error;
44
45 static void convert_mode(XDGAMode *mode, LPDDHALMODEINFO info)
46 {
47   info->dwWidth        = mode->viewportWidth;
48   info->dwHeight       = mode->viewportHeight;
49   info->wRefreshRate   = mode->verticalRefresh;
50   info->lPitch         = mode->bytesPerScanline;
51   info->dwBPP          = (mode->depth < 24) ? mode->depth : mode->bitsPerPixel;
52   info->wFlags         = (mode->depth == 8) ? DDMODEINFO_PALETTIZED : 0;
53   info->dwRBitMask     = mode->redMask;
54   info->dwGBitMask     = mode->greenMask;
55   info->dwBBitMask     = mode->blueMask;
56   info->dwAlphaBitMask = 0;
57   TRACE(" width=%ld, height=%ld, bpp=%ld, refresh=%d\n",
58         info->dwWidth, info->dwHeight, info->dwBPP, info->wRefreshRate);
59 }
60
61 static int DGA2ErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
62 {
63     return 1;
64 }
65
66 void X11DRV_XF86DGA2_Init(void)
67 {
68   int nmodes, major, minor, i;
69   Bool ok;
70
71   if (xf86dga2_modes) return; /* already initialized? */
72
73   /* if in desktop mode, don't use DGA */
74   if (root_window != DefaultRootWindow(gdi_display)) return;
75
76   if (!usedga) return;
77
78   if (!TSXDGAQueryExtension(gdi_display, &dga_event, &dga_error)) return;
79
80   X11DRV_expect_error(gdi_display, DGA2ErrorHandler, NULL);
81   ok = TSXDGAQueryVersion(gdi_display, &major, &minor);
82   if (X11DRV_check_error()) ok = FALSE;
83   if (!ok) return;
84
85   if (major < 2) return; /* only bother with DGA 2+ */
86
87   /* test that it works */
88   if (!TSXDGAOpenFramebuffer(gdi_display, DefaultScreen(gdi_display))) {
89     WARN("disabling XF86DGA2 (insufficient permissions?)\n");
90     return;
91   }
92   TSXDGACloseFramebuffer(gdi_display, DefaultScreen(gdi_display));
93
94   /* retrieve modes */
95   modes = TSXDGAQueryModes(gdi_display, DefaultScreen(gdi_display), &nmodes);
96   if (!modes) return;
97
98   TRACE("DGA modes: count=%d\n", nmodes);
99
100   xf86dga2_mode_count = nmodes+1;
101   xf86dga2_modes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DDHALMODEINFO) * (nmodes+1));
102
103   /* make dummy mode for exiting DGA */
104   memset(&xf86dga2_modes[0], 0, sizeof(xf86dga2_modes[0]));
105
106   /* convert modes to DDHALMODEINFO format */
107   for (i=0; i<nmodes; i++)
108     convert_mode(&modes[i], &xf86dga2_modes[i+1]);
109
110   TRACE("Enabling XF86DGA2 mode\n");
111 }
112
113 void X11DRV_XF86DGA2_Cleanup(void)
114 {
115   if (modes) TSXFree(modes);
116 }
117
118 static XDGADevice *dga_dev;
119
120 static VIDMEM dga_mem = {
121   VIDMEM_ISRECTANGULAR | VIDMEM_ISHEAP
122 };
123
124 static DWORD PASCAL X11DRV_XF86DGA2_SetMode(LPDDHAL_SETMODEDATA data)
125 {
126   LPDDRAWI_DIRECTDRAW_LCL ddlocal = data->lpDD->lpExclusiveOwner;
127   DWORD vram;
128   Display *display = gdi_display;
129
130   data->ddRVal = DD_OK;
131   if (data->dwModeIndex) {
132     /* enter DGA */
133     XDGADevice *new_dev = NULL;
134     if (dga_dev || TSXDGAOpenFramebuffer(display, DefaultScreen(display)))
135       new_dev = TSXDGASetMode(display, DefaultScreen(display), modes[data->dwModeIndex-1].num);
136     if (new_dev) {
137       TSXDGASetViewport(display, DefaultScreen(display), 0, 0, XDGAFlipImmediate);
138       if (dga_dev) {
139         VirtualFree(dga_dev->data, 0, MEM_RELEASE);
140         TSXFree(dga_dev);
141       } else {
142         TSXDGASelectInput(display, DefaultScreen(display),
143                           KeyPressMask|KeyReleaseMask|
144                           ButtonPressMask|ButtonReleaseMask|
145                           PointerMotionMask);
146         X11DRV_EVENT_SetDGAStatus((HWND)ddlocal->hWnd, dga_event);
147         X11DRV_EVENT_SetInputMethod(X11DRV_INPUT_RELATIVE);
148       }
149       dga_dev = new_dev;
150       vram = dga_dev->mode.bytesPerScanline * dga_dev->mode.imageHeight;
151       VirtualAlloc(dga_dev->data, vram, MEM_RESERVE|MEM_SYSTEM, PAGE_READWRITE);
152       dga_mem.fpStart = (FLATPTR)dga_dev->data;
153       dga_mem.u1.dwWidth = dga_dev->mode.bytesPerScanline;
154       dga_mem.u2.dwHeight = dga_dev->mode.imageHeight;
155       X11DRV_DDHAL_SwitchMode(data->dwModeIndex, dga_dev->data, &dga_mem);
156       X11DRV_DD_IsDirect = TRUE;
157     }
158     else {
159       ERR("failed\n");
160       if (!dga_dev) TSXDGACloseFramebuffer(display, DefaultScreen(display));
161       data->ddRVal = DDERR_GENERIC;
162     }
163   }
164   else if (dga_dev) {
165     /* exit DGA */
166     X11DRV_DD_IsDirect = FALSE;
167     X11DRV_DDHAL_SwitchMode(0, NULL, NULL);
168     TSXDGASetMode(display, DefaultScreen(display), 0);
169     VirtualFree(dga_dev->data, 0, MEM_RELEASE);
170     X11DRV_EVENT_SetInputMethod(X11DRV_INPUT_ABSOLUTE);
171     X11DRV_EVENT_SetDGAStatus(0, -1);
172     TSXFree(dga_dev);
173     TSXDGACloseFramebuffer(display, DefaultScreen(display));
174     dga_dev = NULL;
175   }
176   return DDHAL_DRIVER_HANDLED;
177 }
178
179 static LPDDHAL_CREATESURFACE X11DRV_XF86DGA2_old_create_surface;
180
181 static DWORD PASCAL X11DRV_XF86DGA2_CreateSurface(LPDDHAL_CREATESURFACEDATA data)
182 {
183   LPDDRAWI_DDRAWSURFACE_LCL lcl = *data->lplpSList;
184   LPDDRAWI_DDRAWSURFACE_GBL gbl = lcl->lpGbl;
185   LPDDSURFACEDESC2 desc = (LPDDSURFACEDESC2)data->lpDDSurfaceDesc;
186   HRESULT hr = DDHAL_DRIVER_NOTHANDLED;
187
188   if (X11DRV_XF86DGA2_old_create_surface)
189     hr = X11DRV_XF86DGA2_old_create_surface(data);
190
191   if (desc->ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | DDSCAPS_BACKBUFFER)) {
192     gbl->fpVidMem = 0; /* tell ddraw to allocate the memory */
193     hr = DDHAL_DRIVER_HANDLED;
194   }
195   return hr;
196 }
197
198 static DWORD PASCAL X11DRV_XF86DGA2_CreatePalette(LPDDHAL_CREATEPALETTEDATA data)
199 {
200   Display *display = gdi_display;
201   data->lpDDPalette->u1.dwReserved1 = TSXDGACreateColormap(display, DefaultScreen(display), dga_dev, AllocAll);
202   if (data->lpColorTable)
203     X11DRV_DDHAL_SetPalEntries(data->lpDDPalette->u1.dwReserved1, 0, 256,
204                                data->lpColorTable);
205   data->ddRVal = DD_OK;
206   return DDHAL_DRIVER_HANDLED;
207 }
208
209 static DWORD PASCAL X11DRV_XF86DGA2_Flip(LPDDHAL_FLIPDATA data)
210 {
211   Display *display = gdi_display;
212   if (data->lpSurfCurr == X11DRV_DD_Primary) {
213     DWORD ofs = data->lpSurfCurr->lpGbl->fpVidMem - dga_mem.fpStart;
214     TSXDGASetViewport(display, DefaultScreen(display),
215                       (ofs % dga_dev->mode.bytesPerScanline)*8/dga_dev->mode.bitsPerPixel,
216                       ofs / dga_dev->mode.bytesPerScanline,
217                       XDGAFlipImmediate);
218   }
219   data->ddRVal = DD_OK;
220   return DDHAL_DRIVER_HANDLED;
221 }
222
223 static DWORD PASCAL X11DRV_XF86DGA2_SetPalette(LPDDHAL_SETPALETTEDATA data)
224 {
225   Display *display = gdi_display;
226   if ((data->lpDDSurface == X11DRV_DD_Primary) &&
227       data->lpDDPalette && data->lpDDPalette->u1.dwReserved1) {
228     TSXDGAInstallColormap(display, DefaultScreen(display), data->lpDDPalette->u1.dwReserved1);
229   }
230   data->ddRVal = DD_OK;
231   return DDHAL_DRIVER_HANDLED;
232 }
233
234 int X11DRV_XF86DGA2_CreateDriver(LPDDHALINFO info)
235 {
236   if (!xf86dga2_mode_count) return 0; /* no DGA */
237
238   info->dwNumModes = xf86dga2_mode_count;
239   info->lpModeInfo = xf86dga2_modes;
240   info->dwModeIndex = 0;
241
242   X11DRV_XF86DGA2_old_create_surface = info->lpDDCallbacks->CreateSurface;
243   info->lpDDCallbacks->SetMode = X11DRV_XF86DGA2_SetMode;
244   info->lpDDCallbacks->CreateSurface = X11DRV_XF86DGA2_CreateSurface;
245   info->lpDDCallbacks->CreatePalette = X11DRV_XF86DGA2_CreatePalette;
246   info->lpDDSurfaceCallbacks->Flip = X11DRV_XF86DGA2_Flip;
247   info->lpDDSurfaceCallbacks->SetPalette = X11DRV_XF86DGA2_SetPalette;
248   return TRUE;
249 }
250
251 #endif /* HAVE_LIBXXF86DGA2 */