Replace a number of calls to WIN_FindWndPtr by WIN_GetPtr.
[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 #define NONAMELESSUNION
26 #define NONAMELESSSTRUCT
27 #include <X11/Xlib.h>
28 #include <X11/extensions/xf86dga.h>
29
30 #include "x11drv.h"
31 #include "x11ddraw.h"
32 #include "dga2.h"
33
34 #include "windef.h"
35 #include "wingdi.h"
36 #include "ddrawi.h"
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
40
41 extern int usedga;
42
43 LPDDHALMODEINFO xf86dga2_modes;
44 unsigned xf86dga2_mode_count;
45 static XDGAMode* modes;
46 static int dga_event, dga_error;
47
48 static void convert_mode(XDGAMode *mode, LPDDHALMODEINFO info)
49 {
50   info->dwWidth        = mode->viewportWidth;
51   info->dwHeight       = mode->viewportHeight;
52   info->wRefreshRate   = mode->verticalRefresh;
53   info->lPitch         = mode->bytesPerScanline;
54   info->dwBPP          = (mode->depth < 24) ? mode->depth : mode->bitsPerPixel;
55   info->wFlags         = (mode->depth == 8) ? DDMODEINFO_PALETTIZED : 0;
56   info->dwRBitMask     = mode->redMask;
57   info->dwGBitMask     = mode->greenMask;
58   info->dwBBitMask     = mode->blueMask;
59   info->dwAlphaBitMask = 0;
60   TRACE(" width=%ld, height=%ld, bpp=%ld, refresh=%d\n",
61         info->dwWidth, info->dwHeight, info->dwBPP, info->wRefreshRate);
62 }
63
64 static int DGA2ErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
65 {
66     return 1;
67 }
68
69 void X11DRV_XF86DGA2_Init(void)
70 {
71   int nmodes, major, minor, i;
72   Bool ok;
73
74   TRACE("\n");
75
76   if (xf86dga2_modes) return; /* already initialized? */
77
78   /* if in desktop mode, don't use DGA */
79   if (root_window != DefaultRootWindow(gdi_display)) return;
80
81   if (!usedga) return;
82
83   wine_tsx11_lock();
84   ok = XDGAQueryExtension(gdi_display, &dga_event, &dga_error);
85   if (ok)
86   {
87       X11DRV_expect_error(gdi_display, DGA2ErrorHandler, NULL);
88       ok = XDGAQueryVersion(gdi_display, &major, &minor);
89       if (X11DRV_check_error()) ok = FALSE;
90   }
91   wine_tsx11_unlock();
92   if (!ok) return;
93
94   if (major < 2) return; /* only bother with DGA 2+ */
95
96   /* test that it works */
97   wine_tsx11_lock();
98   X11DRV_expect_error(gdi_display, DGA2ErrorHandler, NULL);
99   ok = XDGAOpenFramebuffer(gdi_display, DefaultScreen(gdi_display));
100   if (X11DRV_check_error()) ok = FALSE;
101   if (ok)
102   {
103       XDGACloseFramebuffer(gdi_display, DefaultScreen(gdi_display));
104       /* retrieve modes */
105       modes = XDGAQueryModes(gdi_display, DefaultScreen(gdi_display), &nmodes);
106       if (!modes) ok = FALSE;
107   }
108   else WARN("disabling XF86DGA2 (insufficient permissions?)\n");
109   wine_tsx11_unlock();
110   if (!ok) return;
111
112   TRACE("DGA modes: count=%d\n", nmodes);
113
114   xf86dga2_mode_count = nmodes+1;
115   xf86dga2_modes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DDHALMODEINFO) * (nmodes+1));
116
117   /* make dummy mode for exiting DGA */
118   memset(&xf86dga2_modes[0], 0, sizeof(xf86dga2_modes[0]));
119
120   /* convert modes to DDHALMODEINFO format */
121   for (i=0; i<nmodes; i++)
122     convert_mode(&modes[i], &xf86dga2_modes[i+1]);
123
124   TRACE("Enabling XF86DGA2 mode\n");
125 }
126
127 void X11DRV_XF86DGA2_Cleanup(void)
128 {
129     wine_tsx11_lock();
130     if (modes) XFree(modes);
131     wine_tsx11_unlock();
132 }
133
134 static XDGADevice *dga_dev;
135
136 static VIDMEM dga_mem = {
137   VIDMEM_ISRECTANGULAR | VIDMEM_ISHEAP
138 };
139
140 static DWORD PASCAL X11DRV_XF86DGA2_SetMode(LPDDHAL_SETMODEDATA data)
141 {
142   LPDDRAWI_DIRECTDRAW_LCL ddlocal = data->lpDD->lpExclusiveOwner;
143   DWORD vram;
144   Display *display = gdi_display;
145
146   data->ddRVal = DD_OK;
147   wine_tsx11_lock();
148   if (data->dwModeIndex) {
149     /* enter DGA */
150     XDGADevice *new_dev = NULL;
151     if (dga_dev || XDGAOpenFramebuffer(display, DefaultScreen(display)))
152       new_dev = XDGASetMode(display, DefaultScreen(display), modes[data->dwModeIndex-1].num);
153     if (new_dev) {
154       XDGASetViewport(display, DefaultScreen(display), 0, 0, XDGAFlipImmediate);
155       if (dga_dev) {
156         VirtualFree(dga_dev->data, 0, MEM_RELEASE);
157         XFree(dga_dev);
158       } else {
159         XDGASelectInput(display, DefaultScreen(display),
160                           KeyPressMask|KeyReleaseMask|
161                           ButtonPressMask|ButtonReleaseMask|
162                           PointerMotionMask);
163         X11DRV_EVENT_SetDGAStatus((HWND)ddlocal->hWnd, dga_event);
164         X11DRV_EVENT_SetInputMethod(X11DRV_INPUT_RELATIVE);
165       }
166       dga_dev = new_dev;
167       vram = dga_dev->mode.bytesPerScanline * dga_dev->mode.imageHeight;
168       VirtualAlloc(dga_dev->data, vram, MEM_SYSTEM, PAGE_READWRITE);
169       dga_mem.fpStart = (FLATPTR)dga_dev->data;
170       dga_mem.u1.dwWidth = dga_dev->mode.bytesPerScanline;
171       dga_mem.u2.dwHeight = dga_dev->mode.imageHeight;
172       X11DRV_DDHAL_SwitchMode(data->dwModeIndex, dga_dev->data, &dga_mem);
173       X11DRV_DD_IsDirect = TRUE;
174     }
175     else {
176       ERR("failed\n");
177       if (!dga_dev) XDGACloseFramebuffer(display, DefaultScreen(display));
178       data->ddRVal = DDERR_GENERIC;
179     }
180   }
181   else if (dga_dev) {
182     /* exit DGA */
183     X11DRV_DD_IsDirect = FALSE;
184     X11DRV_DDHAL_SwitchMode(0, NULL, NULL);
185     XDGASetMode(display, DefaultScreen(display), 0);
186     VirtualFree(dga_dev->data, 0, MEM_RELEASE);
187     X11DRV_EVENT_SetInputMethod(X11DRV_INPUT_ABSOLUTE);
188     X11DRV_EVENT_SetDGAStatus(0, -1);
189     XFree(dga_dev);
190     XDGACloseFramebuffer(display, DefaultScreen(display));
191     dga_dev = NULL;
192   }
193   wine_tsx11_unlock();
194   return DDHAL_DRIVER_HANDLED;
195 }
196
197 static LPDDHAL_CREATESURFACE X11DRV_XF86DGA2_old_create_surface;
198
199 static DWORD PASCAL X11DRV_XF86DGA2_CreateSurface(LPDDHAL_CREATESURFACEDATA data)
200 {
201   LPDDRAWI_DDRAWSURFACE_LCL lcl = *data->lplpSList;
202   LPDDRAWI_DDRAWSURFACE_GBL gbl = lcl->lpGbl;
203   LPDDSURFACEDESC2 desc = (LPDDSURFACEDESC2)data->lpDDSurfaceDesc;
204   HRESULT hr = DDHAL_DRIVER_NOTHANDLED;
205
206   if (X11DRV_XF86DGA2_old_create_surface)
207     hr = X11DRV_XF86DGA2_old_create_surface(data);
208
209   if (desc->ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | DDSCAPS_BACKBUFFER)) {
210     gbl->fpVidMem = 0; /* tell ddraw to allocate the memory */
211     hr = DDHAL_DRIVER_HANDLED;
212   }
213   return hr;
214 }
215
216 static DWORD PASCAL X11DRV_XF86DGA2_CreatePalette(LPDDHAL_CREATEPALETTEDATA data)
217 {
218   Display *display = gdi_display;
219   wine_tsx11_lock();
220   data->lpDDPalette->u1.dwReserved1 = XDGACreateColormap(display, DefaultScreen(display),
221                                                          dga_dev, AllocAll);
222   wine_tsx11_unlock();
223   if (data->lpColorTable)
224     X11DRV_DDHAL_SetPalEntries(data->lpDDPalette->u1.dwReserved1, 0, 256,
225                                data->lpColorTable);
226   data->ddRVal = DD_OK;
227   return DDHAL_DRIVER_HANDLED;
228 }
229
230 static DWORD PASCAL X11DRV_XF86DGA2_Flip(LPDDHAL_FLIPDATA data)
231 {
232   Display *display = gdi_display;
233   if (data->lpSurfCurr == X11DRV_DD_Primary) {
234     DWORD ofs = data->lpSurfCurr->lpGbl->fpVidMem - dga_mem.fpStart;
235     wine_tsx11_lock();
236     XDGASetViewport(display, DefaultScreen(display),
237                     (ofs % dga_dev->mode.bytesPerScanline)*8/dga_dev->mode.bitsPerPixel,
238                     ofs / dga_dev->mode.bytesPerScanline,
239                     XDGAFlipImmediate);
240     wine_tsx11_unlock();
241   }
242   data->ddRVal = DD_OK;
243   return DDHAL_DRIVER_HANDLED;
244 }
245
246 static DWORD PASCAL X11DRV_XF86DGA2_SetPalette(LPDDHAL_SETPALETTEDATA data)
247 {
248   Display *display = gdi_display;
249   if ((data->lpDDSurface == X11DRV_DD_Primary) &&
250       data->lpDDPalette && data->lpDDPalette->u1.dwReserved1)
251   {
252       wine_tsx11_lock();
253       XDGAInstallColormap(display, DefaultScreen(display), data->lpDDPalette->u1.dwReserved1);
254       wine_tsx11_unlock();
255   }
256   data->ddRVal = DD_OK;
257   return DDHAL_DRIVER_HANDLED;
258 }
259
260 int X11DRV_XF86DGA2_CreateDriver(LPDDHALINFO info)
261 {
262   if (!xf86dga2_mode_count) return 0; /* no DGA */
263
264   info->dwNumModes = xf86dga2_mode_count;
265   info->lpModeInfo = xf86dga2_modes;
266   info->dwModeIndex = 0;
267
268   X11DRV_XF86DGA2_old_create_surface = info->lpDDCallbacks->CreateSurface;
269   info->lpDDCallbacks->SetMode = X11DRV_XF86DGA2_SetMode;
270   info->lpDDCallbacks->CreateSurface = X11DRV_XF86DGA2_CreateSurface;
271   info->lpDDCallbacks->CreatePalette = X11DRV_XF86DGA2_CreatePalette;
272   info->lpDDSurfaceCallbacks->Flip = X11DRV_XF86DGA2_Flip;
273   info->lpDDSurfaceCallbacks->SetPalette = X11DRV_XF86DGA2_SetPalette;
274   return TRUE;
275 }
276
277 #endif /* HAVE_LIBXXF86DGA2 */