src/video/dga/SDL_dgavideo.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 08 May 2006 06:54:20 +0000
changeset 1784 45669d4efd02
parent 1575 3ba88cb7eb1b
child 1785 dcec47a019e2
permissions -rw-r--r--
Disable the screensaver in DGA mode, which is even more important than X11...
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 /* DGA 2.0 based SDL video driver implementation.
    25 */
    26 
    27 #include <stdio.h>
    28 
    29 #include <X11/Xlib.h>
    30 #include "../Xext/extensions/xf86dga.h"
    31 
    32 #include "SDL_video.h"
    33 #include "SDL_mouse.h"
    34 #include "../SDL_sysvideo.h"
    35 #include "../SDL_pixels_c.h"
    36 #include "../../events/SDL_events_c.h"
    37 #include "SDL_dgavideo.h"
    38 #include "SDL_dgamouse_c.h"
    39 #include "SDL_dgaevents_c.h"
    40 
    41 /* get function pointers... */
    42 #include "../x11/SDL_x11dyn.h"
    43 
    44 /* Heheh we're using X11 event code */
    45 extern void X11_SaveScreenSaver(Display *display, int *saved_timeout, BOOL *dpms);
    46 extern void X11_DisableScreenSaver(Display *display);
    47 extern void X11_RestoreScreenSaver(Display *display, int saved_timeout, BOOL dpms);
    48 
    49 /* Initialization/Query functions */
    50 static int DGA_VideoInit(_THIS, SDL_PixelFormat *vformat);
    51 static SDL_Rect **DGA_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
    52 static SDL_Surface *DGA_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
    53 static int DGA_SetColors(_THIS, int firstcolor, int ncolors,
    54 			 SDL_Color *colors);
    55 static int DGA_SetGammaRamp(_THIS, Uint16 *ramp);
    56 static void DGA_VideoQuit(_THIS);
    57 
    58 /* Hardware surface functions */
    59 static int DGA_InitHWSurfaces(_THIS, SDL_Surface *screen, Uint8 *base, int size);
    60 static void DGA_FreeHWSurfaces(_THIS);
    61 static int DGA_AllocHWSurface(_THIS, SDL_Surface *surface);
    62 static int DGA_FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color);
    63 static int DGA_CheckHWBlit(_THIS, SDL_Surface *src, SDL_Surface *dst);
    64 static int DGA_LockHWSurface(_THIS, SDL_Surface *surface);
    65 static void DGA_UnlockHWSurface(_THIS, SDL_Surface *surface);
    66 static void DGA_FreeHWSurface(_THIS, SDL_Surface *surface);
    67 static int DGA_FlipHWSurface(_THIS, SDL_Surface *surface);
    68 
    69 /* DGA driver bootstrap functions */
    70 
    71 static int DGA_Available(void)
    72 {
    73 	const char *display = NULL;
    74 	Display *dpy = NULL;
    75 	int available = 0;
    76 
    77 	/* The driver is available is available if the display is local
    78 	   and the DGA 2.0+ extension is available, and we can map mem.
    79 	*/
    80 	if ( SDL_X11_LoadSymbols() ) {
    81 		if ( (SDL_strncmp(XDisplayName(display), ":", 1) == 0) ||
    82 		     (SDL_strncmp(XDisplayName(display), "unix:", 5) == 0) ) {
    83 			dpy = XOpenDisplay(display);
    84 			if ( dpy ) {
    85 				int events, errors, major, minor;
    86 
    87 				if ( SDL_NAME(XDGAQueryExtension)(dpy, &events, &errors) &&
    88 				     SDL_NAME(XDGAQueryVersion)(dpy, &major, &minor) ) {
    89 					int screen;
    90 
    91 					screen = DefaultScreen(dpy);
    92 					if ( (major >= 2) && 
    93 					     SDL_NAME(XDGAOpenFramebuffer)(dpy, screen) ) {
    94 						available = 1;
    95 						SDL_NAME(XDGACloseFramebuffer)(dpy, screen);
    96 					}
    97 				}
    98 				XCloseDisplay(dpy);
    99 			}
   100 		}
   101 		SDL_X11_UnloadSymbols();
   102 	}
   103 	return(available);
   104 }
   105 
   106 static void DGA_DeleteDevice(SDL_VideoDevice *device)
   107 {
   108 	if (device != NULL) {
   109 		SDL_free(device->hidden);
   110 		SDL_free(device);
   111 		SDL_X11_UnloadSymbols();
   112 	}
   113 }
   114 
   115 static SDL_VideoDevice *DGA_CreateDevice(int devindex)
   116 {
   117 	SDL_VideoDevice *device = NULL;
   118 
   119 	/* Initialize all variables that we clean on shutdown */
   120 	if (SDL_X11_LoadSymbols()) {
   121 		device = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice));
   122 		if ( device ) {
   123 			SDL_memset(device, 0, (sizeof *device));
   124 			device->hidden = (struct SDL_PrivateVideoData *)
   125 					SDL_malloc((sizeof *device->hidden));
   126 		}
   127 		if ( (device == NULL) || (device->hidden == NULL) ) {
   128 			SDL_OutOfMemory();
   129 			if ( device ) {
   130 				SDL_free(device);
   131 			}
   132 			SDL_X11_UnloadSymbols();
   133 			return(0);
   134 		}
   135 		SDL_memset(device->hidden, 0, (sizeof *device->hidden));
   136 
   137 		/* Set the function pointers */
   138 		device->VideoInit = DGA_VideoInit;
   139 		device->ListModes = DGA_ListModes;
   140 		device->SetVideoMode = DGA_SetVideoMode;
   141 		device->SetColors = DGA_SetColors;
   142 		device->UpdateRects = NULL;
   143 		device->VideoQuit = DGA_VideoQuit;
   144 		device->AllocHWSurface = DGA_AllocHWSurface;
   145 		device->CheckHWBlit = DGA_CheckHWBlit;
   146 		device->FillHWRect = DGA_FillHWRect;
   147 		device->SetHWColorKey = NULL;
   148 		device->SetHWAlpha = NULL;
   149 		device->LockHWSurface = DGA_LockHWSurface;
   150 		device->UnlockHWSurface = DGA_UnlockHWSurface;
   151 		device->FlipHWSurface = DGA_FlipHWSurface;
   152 		device->FreeHWSurface = DGA_FreeHWSurface;
   153 		device->SetGammaRamp = DGA_SetGammaRamp;
   154 		device->GetGammaRamp = NULL;
   155 		device->SetCaption = NULL;
   156 		device->SetIcon = NULL;
   157 		device->IconifyWindow = NULL;
   158 		device->GrabInput = NULL;
   159 		device->GetWMInfo = NULL;
   160 		device->InitOSKeymap = DGA_InitOSKeymap;
   161 		device->PumpEvents = DGA_PumpEvents;
   162 
   163 		device->free = DGA_DeleteDevice;
   164 	}
   165 
   166 	return device;
   167 }
   168 
   169 VideoBootStrap DGA_bootstrap = {
   170 	"dga", "XFree86 DGA 2.0",
   171 	DGA_Available, DGA_CreateDevice
   172 };
   173 
   174 static int DGA_AddMode(_THIS, int bpp, int w, int h)
   175 {
   176 	SDL_Rect *mode;
   177 	int i, index;
   178 	int next_mode;
   179 
   180 	/* Check to see if we already have this mode */
   181 	if ( bpp < 8 ) {  /* Not supported */
   182 		return(0);
   183 	}
   184 	index = ((bpp+7)/8)-1;
   185 	for ( i=0; i<SDL_nummodes[index]; ++i ) {
   186 		mode = SDL_modelist[index][i];
   187 		if ( (mode->w == w) && (mode->h == h) ) {
   188 			return(0);
   189 		}
   190 	}
   191 
   192 	/* Set up the new video mode rectangle */
   193 	mode = (SDL_Rect *)SDL_malloc(sizeof *mode);
   194 	if ( mode == NULL ) {
   195 		SDL_OutOfMemory();
   196 		return(-1);
   197 	}
   198 	mode->x = 0;
   199 	mode->y = 0;
   200 	mode->w = w;
   201 	mode->h = h;
   202 
   203 	/* Allocate the new list of modes, and fill in the new mode */
   204 	next_mode = SDL_nummodes[index];
   205 	SDL_modelist[index] = (SDL_Rect **)
   206 	       SDL_realloc(SDL_modelist[index], (1+next_mode+1)*sizeof(SDL_Rect *));
   207 	if ( SDL_modelist[index] == NULL ) {
   208 		SDL_OutOfMemory();
   209 		SDL_nummodes[index] = 0;
   210 		SDL_free(mode);
   211 		return(-1);
   212 	}
   213 	SDL_modelist[index][next_mode] = mode;
   214 	SDL_modelist[index][next_mode+1] = NULL;
   215 	SDL_nummodes[index]++;
   216 
   217 	return(0);
   218 }
   219 
   220 /* This whole function is a hack. :) */
   221 static Uint32 get_video_size(_THIS)
   222 {
   223 	/* This is a non-exported function from libXxf86dga.a */
   224 	extern unsigned char *SDL_NAME(XDGAGetMappedMemory)(int screen);
   225 	FILE *proc;
   226 	unsigned long mem;
   227 	unsigned start, stop;
   228 	char line[BUFSIZ];
   229 	Uint32 size;
   230 
   231 	mem = (unsigned long)SDL_NAME(XDGAGetMappedMemory)(DGA_Screen);
   232 	size = 0;
   233 	proc = fopen("/proc/self/maps", "r");
   234 	if ( proc ) {
   235 		while ( fgets(line, sizeof(line)-1, proc) ) {
   236 			SDL_sscanf(line, "%x-%x", &start, &stop);
   237 			if ( start == mem ) {
   238 				size = (Uint32)((stop-start)/1024);
   239 				break;
   240 			}
   241 		}
   242 		fclose(proc);
   243 	}
   244 	return(size);
   245 }
   246 
   247 #ifdef DGA_DEBUG
   248 static void PrintMode(SDL_NAME(XDGAMode) *mode)
   249 {
   250 	printf("Mode: %s (%dx%d) at %d bpp (%f refresh, %d pitch) num: %d\n",
   251 		mode->name,
   252 		mode->viewportWidth, mode->viewportHeight,
   253 		mode->depth == 24 ? mode->bitsPerPixel : mode->depth,
   254 		mode->verticalRefresh, mode->bytesPerScanline, mode->num);
   255 	printf("\tRGB: 0x%8.8x 0x%8.8x 0x%8.8x (%d - %s)\n",
   256 		mode->redMask, mode->greenMask, mode->blueMask,
   257 		mode->visualClass,
   258 		mode->visualClass == TrueColor ? "truecolor" :
   259 		mode->visualClass == DirectColor ? "directcolor" :
   260 		mode->visualClass == PseudoColor ? "pseudocolor" : "unknown");
   261 	printf("\tFlags: ");
   262 	if ( mode->flags & XDGAConcurrentAccess )
   263 		printf(" XDGAConcurrentAccess");
   264 	if ( mode->flags & XDGASolidFillRect )
   265 		printf(" XDGASolidFillRect");
   266 	if ( mode->flags & XDGABlitRect )
   267 		printf(" XDGABlitRect");
   268 	if ( mode->flags & XDGABlitTransRect )
   269 		printf(" XDGABlitTransRect");
   270 	if ( mode->flags & XDGAPixmap )
   271 		printf(" XDGAPixmap");
   272 	if ( mode->flags & XDGAInterlaced )
   273 		printf(" XDGAInterlaced");
   274 	if ( mode->flags & XDGADoublescan )
   275 		printf(" XDGADoublescan");
   276 	if ( mode->viewportFlags & XDGAFlipRetrace )
   277 		printf(" XDGAFlipRetrace");
   278 	if ( mode->viewportFlags & XDGAFlipImmediate )
   279 		printf(" XDGAFlipImmediate");
   280 	printf("\n");
   281 }
   282 #endif /* DGA_DEBUG */
   283 
   284 static int cmpmodes(const void *va, const void *vb)
   285 {
   286     const SDL_NAME(XDGAMode) *a = (const SDL_NAME(XDGAMode) *)va;
   287     const SDL_NAME(XDGAMode) *b = (const SDL_NAME(XDGAMode) *)vb;
   288 
   289     /* Prefer DirectColor visuals for otherwise equal modes */
   290     if ( (a->viewportWidth == b->viewportWidth) &&
   291          (b->viewportHeight == a->viewportHeight) ) {
   292         if ( a->visualClass == DirectColor )
   293             return -1;
   294         if ( b->visualClass == DirectColor )
   295             return 1;
   296         return 0;
   297     } else if ( a->viewportWidth == b->viewportWidth ) {
   298         return b->viewportHeight - a->viewportHeight;
   299     } else {
   300         return b->viewportWidth - a->viewportWidth;
   301     }
   302 }
   303 static void UpdateHWInfo(_THIS, SDL_NAME(XDGAMode) *mode)
   304 {
   305 	this->info.wm_available = 0;
   306 	this->info.hw_available = 1;
   307 	if ( mode->flags & XDGABlitRect ) {
   308 		this->info.blit_hw = 1;
   309 	} else {
   310 		this->info.blit_hw = 0;
   311 	}
   312 	if ( mode->flags & XDGABlitTransRect ) {
   313 		this->info.blit_hw_CC = 1;
   314 	} else {
   315 		this->info.blit_hw_CC = 0;
   316 	}
   317 	if ( mode->flags & XDGASolidFillRect ) {
   318 		this->info.blit_fill = 1;
   319 	} else {
   320 		this->info.blit_fill = 0;
   321 	}
   322 	this->info.video_mem = get_video_size(this);
   323 }
   324 
   325 static int DGA_VideoInit(_THIS, SDL_PixelFormat *vformat)
   326 {
   327 	const char *display;
   328 	int event_base, error_base;
   329 	int major_version, minor_version;
   330 	Visual *visual;
   331 	SDL_NAME(XDGAMode) *modes;
   332 	int i, num_modes;
   333 
   334 	/* Open the X11 display */
   335 	display = NULL;		/* Get it from DISPLAY environment variable */
   336 
   337 	DGA_Display = XOpenDisplay(display);
   338 	if ( DGA_Display == NULL ) {
   339 		SDL_SetError("Couldn't open X11 display");
   340 		return(-1);
   341 	}
   342 
   343 	/* Check for the DGA extension */
   344 	if ( ! SDL_NAME(XDGAQueryExtension)(DGA_Display, &event_base, &error_base) ||
   345 	     ! SDL_NAME(XDGAQueryVersion)(DGA_Display, &major_version, &minor_version) ) {
   346 		SDL_SetError("DGA extension not available");
   347 		XCloseDisplay(DGA_Display);
   348 		return(-1);
   349 	}
   350 	if ( major_version < 2 ) {
   351 		SDL_SetError("DGA driver requires DGA 2.0 or newer");
   352 		XCloseDisplay(DGA_Display);
   353 		return(-1);
   354 	}
   355 	DGA_event_base = event_base;
   356 
   357 	/* Determine the current screen size */
   358 	this->info.current_w = DisplayWidth(DGA_Display, DGA_Screen);
   359 	this->info.current_h = DisplayHeight(DGA_Display, DGA_Screen);
   360 
   361 	/* Determine the current screen depth */
   362 	visual = DefaultVisual(DGA_Display, DGA_Screen);
   363 	{
   364 		XPixmapFormatValues *pix_format;
   365 		int i, num_formats;
   366 
   367 		vformat->BitsPerPixel = DefaultDepth(DGA_Display, DGA_Screen);
   368 		pix_format = XListPixmapFormats(DGA_Display, &num_formats);
   369 		if ( pix_format == NULL ) {
   370 			SDL_SetError("Couldn't determine screen formats");
   371 			XCloseDisplay(DGA_Display);
   372 			return(-1);
   373 		}
   374 		for ( i=0; i<num_formats; ++i ) {
   375 			if ( vformat->BitsPerPixel == pix_format[i].depth )
   376 				break;
   377 		}
   378 		if ( i != num_formats )
   379 			vformat->BitsPerPixel = pix_format[i].bits_per_pixel;
   380 		XFree((char *)pix_format);
   381 	}
   382 	if ( vformat->BitsPerPixel > 8 ) {
   383 		vformat->Rmask = visual->red_mask;
   384 		vformat->Gmask = visual->green_mask;
   385 		vformat->Bmask = visual->blue_mask;
   386 	}
   387 
   388 	/* Open access to the framebuffer */
   389 	if ( ! SDL_NAME(XDGAOpenFramebuffer)(DGA_Display, DGA_Screen) ) {
   390 		SDL_SetError("Unable to map the video memory");
   391 		XCloseDisplay(DGA_Display);
   392 		return(-1);
   393 	}
   394 
   395 	/* Save DPMS and screensaver settings */
   396 	X11_SaveScreenSaver(DGA_Display, &screensaver_timeout, &dpms_enabled);
   397 	X11_DisableScreenSaver(DGA_Display);
   398 
   399 	/* Query for the list of available video modes */
   400 	modes = SDL_NAME(XDGAQueryModes)(DGA_Display, DGA_Screen, &num_modes);
   401 	SDL_qsort(modes, num_modes, sizeof *modes, cmpmodes);
   402 	for ( i=0; i<num_modes; ++i ) {
   403 #ifdef DGA_DEBUG
   404 		PrintMode(&modes[i]);
   405 #endif
   406 		if ( (modes[i].visualClass == PseudoColor) ||
   407 		     (modes[i].visualClass == DirectColor) ||
   408 		     (modes[i].visualClass == TrueColor) ) {
   409 			DGA_AddMode(this, modes[i].bitsPerPixel,
   410 			            modes[i].viewportWidth,
   411 			            modes[i].viewportHeight);
   412 		}
   413 	}
   414 	UpdateHWInfo(this, modes);
   415 	XFree(modes);
   416 
   417 	/* Create the hardware surface lock mutex */
   418 	hw_lock = SDL_CreateMutex();
   419 	if ( hw_lock == NULL ) {
   420 		SDL_SetError("Unable to create lock mutex");
   421 		DGA_VideoQuit(this);
   422 		return(-1);
   423 	}
   424 
   425 #ifdef LOCK_DGA_DISPLAY
   426 	/* Create the event lock so we're thread-safe.. :-/ */
   427 	event_lock = SDL_CreateMutex();
   428 #endif /* LOCK_DGA_DISPLAY */
   429 
   430 	/* We're done! */
   431 	return(0);
   432 }
   433 
   434 SDL_Rect **DGA_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
   435 {
   436 	return(SDL_modelist[((format->BitsPerPixel+7)/8)-1]);
   437 }
   438 
   439 /* Various screen update functions available */
   440 static void DGA_DirectUpdate(_THIS, int numrects, SDL_Rect *rects);
   441 
   442 SDL_Surface *DGA_SetVideoMode(_THIS, SDL_Surface *current,
   443 				int width, int height, int bpp, Uint32 flags)
   444 {
   445 	SDL_NAME(XDGAMode) *modes;
   446 	int i, num_modes;
   447 	SDL_NAME(XDGADevice) *mode;
   448 	int screen_len;
   449 	Uint8 *surfaces_mem;
   450 	int surfaces_len;
   451 
   452 	/* Free any previous colormap */
   453 	if ( DGA_colormap ) {
   454 		XFreeColormap(DGA_Display, DGA_colormap);
   455 		DGA_colormap = 0;
   456 	}
   457 
   458 	/* Search for a matching video mode */
   459 	modes = SDL_NAME(XDGAQueryModes)(DGA_Display, DGA_Screen, &num_modes);
   460 	SDL_qsort(modes, num_modes, sizeof *modes, cmpmodes);
   461 	for ( i=0; i<num_modes; ++i ) {
   462 		int depth;
   463 
   464 		
   465 		depth = modes[i].depth;
   466 		if ( depth == 24 ) { /* Distinguish between 24 and 32 bpp */
   467 			depth = modes[i].bitsPerPixel;
   468 		}
   469 		if ( (depth == bpp) &&
   470 		     (modes[i].viewportWidth == width) &&
   471 		     (modes[i].viewportHeight == height) &&
   472 		     ((modes[i].visualClass == PseudoColor) ||
   473 		      (modes[i].visualClass == DirectColor) ||
   474 		      (modes[i].visualClass == TrueColor)) ) {
   475 			break;
   476 		}
   477 	}
   478 	if ( i == num_modes ) {
   479 		SDL_SetError("No matching video mode found");
   480 		return(NULL);
   481 	}
   482 
   483 	/* Set the video mode */
   484 	mode = SDL_NAME(XDGASetMode)(DGA_Display, DGA_Screen, modes[i].num);
   485 	XFree(modes);
   486 	if ( mode == NULL ) {
   487 		SDL_SetError("Unable to switch to requested mode");
   488 		return(NULL);
   489 	}
   490 	DGA_visualClass = mode->mode.visualClass;
   491 	memory_base = (Uint8 *)mode->data;
   492 	memory_pitch = mode->mode.bytesPerScanline;
   493 
   494 	/* Set up the new mode framebuffer */
   495 	current->flags = (SDL_FULLSCREEN|SDL_HWSURFACE);
   496 	current->w = mode->mode.viewportWidth;
   497 	current->h = mode->mode.viewportHeight;
   498 	current->pitch = memory_pitch;
   499 	current->pixels = memory_base;
   500 	if ( ! SDL_ReallocFormat(current, mode->mode.bitsPerPixel,
   501 	                                  mode->mode.redMask,
   502 	                                  mode->mode.greenMask,
   503 	                                  mode->mode.blueMask, 0) ) {
   504 		return(NULL);
   505 	}
   506 	screen_len = current->h*current->pitch;
   507 
   508 	/* Create a colormap if necessary */
   509 	if ( (DGA_visualClass == PseudoColor) ||
   510              (DGA_visualClass == DirectColor) ) {
   511 		DGA_colormap = SDL_NAME(XDGACreateColormap)(DGA_Display, DGA_Screen,
   512 							mode, AllocAll);
   513 		if ( DGA_visualClass == PseudoColor ) {
   514 			current->flags |= SDL_HWPALETTE;
   515 		} else {
   516 	    		/* Initialize the colormap to the identity mapping */
   517 	    		SDL_GetGammaRamp(0, 0, 0);
   518 	    		this->screen = current;
   519 	    		DGA_SetGammaRamp(this, this->gamma);
   520 			this->screen = NULL;
   521 		}
   522 	} else {
   523 		DGA_colormap = SDL_NAME(XDGACreateColormap)(DGA_Display, DGA_Screen,
   524 							mode, AllocNone);
   525 	}
   526 	SDL_NAME(XDGAInstallColormap)(DGA_Display, DGA_Screen, DGA_colormap);
   527 
   528 	/* Update the hardware capabilities */
   529 	UpdateHWInfo(this, &mode->mode);
   530 
   531 	/* Set up the information for hardware surfaces */
   532 	surfaces_mem = (Uint8 *)current->pixels + screen_len;
   533 	surfaces_len = (mode->mode.imageHeight*current->pitch - screen_len);
   534 
   535 	/* Update for double-buffering, if we can */
   536 	SDL_NAME(XDGASetViewport)(DGA_Display, DGA_Screen, 0, 0, XDGAFlipRetrace);
   537 	if ( flags & SDL_DOUBLEBUF ) {
   538 		if ( mode->mode.imageHeight >= (current->h*2) ) {
   539 			current->flags |= SDL_DOUBLEBUF;
   540 			flip_page = 0;
   541 			flip_yoffset[0] = 0;
   542 			flip_yoffset[1] = current->h;
   543 			flip_address[0] = memory_base;
   544 			flip_address[1] = memory_base+screen_len;
   545 			surfaces_mem += screen_len;
   546 			surfaces_len -= screen_len;
   547 		}
   548 	}
   549 
   550 	/* Allocate memory tracking for hardware surfaces */
   551 	DGA_FreeHWSurfaces(this);
   552 	if ( surfaces_len < 0 ) {
   553 		surfaces_len = 0;
   554 	}
   555 	DGA_InitHWSurfaces(this, current, surfaces_mem, surfaces_len);
   556 
   557 	/* Expose the back buffer as surface memory */
   558 	if ( current->flags & SDL_DOUBLEBUF ) {
   559 		this->screen = current;
   560 		DGA_FlipHWSurface(this, current);
   561 		this->screen = NULL;
   562 	}
   563 
   564 	/* Set the update rectangle function */
   565 	this->UpdateRects = DGA_DirectUpdate;
   566 
   567 	/* Enable mouse and keyboard support */
   568 	{ long input_mask;
   569 	  input_mask = (KeyPressMask | KeyReleaseMask);
   570 	  input_mask |= (ButtonPressMask | ButtonReleaseMask);
   571 	  input_mask |= PointerMotionMask;
   572 	  SDL_NAME(XDGASelectInput)(DGA_Display, DGA_Screen, input_mask);
   573 	}
   574 
   575 	/* We're done */
   576 	return(current);
   577 }
   578 
   579 #ifdef DGA_DEBUG
   580 static void DGA_DumpHWSurfaces(_THIS)
   581 {
   582 	vidmem_bucket *bucket;
   583 
   584 	printf("Memory left: %d (%d total)\n", surfaces_memleft, surfaces_memtotal);
   585 	printf("\n");
   586 	printf("         Base  Size\n");
   587 	for ( bucket=&surfaces; bucket; bucket=bucket->next ) {
   588 		printf("Bucket:  %p, %d (%s)\n", bucket->base, bucket->size, bucket->used ? "used" : "free");
   589 		if ( bucket->prev ) {
   590 			if ( bucket->base != bucket->prev->base+bucket->prev->size ) {
   591 				printf("Warning, corrupt bucket list! (prev)\n");
   592 			}
   593 		} else {
   594 			if ( bucket != &surfaces ) {
   595 				printf("Warning, corrupt bucket list! (!prev)\n");
   596 			}
   597 		}
   598 		if ( bucket->next ) {
   599 			if ( bucket->next->base != bucket->base+bucket->size ) {
   600 				printf("Warning, corrupt bucket list! (next)\n");
   601 			}
   602 		}
   603 	}
   604 	printf("\n");
   605 }
   606 #endif
   607 
   608 static int DGA_InitHWSurfaces(_THIS, SDL_Surface *screen, Uint8 *base, int size)
   609 {
   610 	vidmem_bucket *bucket;
   611 
   612 	surfaces_memtotal = size;
   613 	surfaces_memleft = size;
   614 
   615 	if ( surfaces_memleft > 0 ) {
   616 		bucket = (vidmem_bucket *)SDL_malloc(sizeof(*bucket));
   617 		if ( bucket == NULL ) {
   618 			SDL_OutOfMemory();
   619 			return(-1);
   620 		}
   621 		bucket->prev = &surfaces;
   622 		bucket->used = 0;
   623 		bucket->dirty = 0;
   624 		bucket->base = base;
   625 		bucket->size = size;
   626 		bucket->next = NULL;
   627 	} else {
   628 		bucket = NULL;
   629 	}
   630 
   631 	surfaces.prev = NULL;
   632 	surfaces.used = 1;
   633 	surfaces.dirty = 0;
   634 	surfaces.base = screen->pixels;
   635 	surfaces.size = (unsigned int)((long)base - (long)surfaces.base);
   636 	surfaces.next = bucket;
   637 	screen->hwdata = (struct private_hwdata *)&surfaces;
   638 	return(0);
   639 }
   640 static void DGA_FreeHWSurfaces(_THIS)
   641 {
   642 	vidmem_bucket *bucket, *freeable;
   643 
   644 	bucket = surfaces.next;
   645 	while ( bucket ) {
   646 		freeable = bucket;
   647 		bucket = bucket->next;
   648 		SDL_free(freeable);
   649 	}
   650 	surfaces.next = NULL;
   651 }
   652 
   653 static __inline__ void DGA_AddBusySurface(SDL_Surface *surface)
   654 {
   655 	((vidmem_bucket *)surface->hwdata)->dirty = 1;
   656 }
   657 
   658 static __inline__ int DGA_IsSurfaceBusy(SDL_Surface *surface)
   659 {
   660 	return ((vidmem_bucket *)surface->hwdata)->dirty;
   661 }
   662 
   663 static __inline__ void DGA_WaitBusySurfaces(_THIS)
   664 {
   665 	vidmem_bucket *bucket;
   666 
   667 	/* Wait for graphic operations to complete */
   668 	SDL_NAME(XDGASync)(DGA_Display, DGA_Screen);
   669 
   670 	/* Clear all surface dirty bits */
   671 	for ( bucket=&surfaces; bucket; bucket=bucket->next ) {
   672 		bucket->dirty = 0;
   673 	}
   674 }
   675 
   676 static int DGA_AllocHWSurface(_THIS, SDL_Surface *surface)
   677 {
   678 	vidmem_bucket *bucket;
   679 	int size;
   680 	int extra;
   681 	int retval = 0;
   682 
   683 /* Temporarily, we only allow surfaces the same width as display.
   684    Some blitters require the pitch between two hardware surfaces
   685    to be the same.  Others have interesting alignment restrictions.
   686 */
   687 if ( surface->pitch > SDL_VideoSurface->pitch ) {
   688 	SDL_SetError("Surface requested wider than screen");
   689 	return(-1);
   690 }
   691 surface->pitch = SDL_VideoSurface->pitch;
   692 	size = surface->h * surface->pitch;
   693 #ifdef DGA_DEBUG
   694 	fprintf(stderr, "Allocating bucket of %d bytes\n", size);
   695 #endif
   696 	LOCK_DISPLAY();
   697 
   698 	/* Quick check for available mem */
   699 	if ( size > surfaces_memleft ) {
   700 		SDL_SetError("Not enough video memory");
   701 		retval = -1;
   702 		goto done;
   703 	}
   704 
   705 	/* Search for an empty bucket big enough */
   706 	for ( bucket=&surfaces; bucket; bucket=bucket->next ) {
   707 		if ( ! bucket->used && (size <= bucket->size) ) {
   708 			break;
   709 		}
   710 	}
   711 	if ( bucket == NULL ) {
   712 		SDL_SetError("Video memory too fragmented");
   713 		retval = -1;
   714 		goto done;
   715 	}
   716 
   717 	/* Create a new bucket for left-over memory */
   718 	extra = (bucket->size - size);
   719 	if ( extra ) {
   720 		vidmem_bucket *newbucket;
   721 
   722 #ifdef DGA_DEBUG
   723 	fprintf(stderr, "Adding new free bucket of %d bytes\n", extra);
   724 #endif
   725 		newbucket = (vidmem_bucket *)SDL_malloc(sizeof(*newbucket));
   726 		if ( newbucket == NULL ) {
   727 			SDL_OutOfMemory();
   728 			retval = -1;
   729 			goto done;
   730 		}
   731 		newbucket->prev = bucket;
   732 		newbucket->used = 0;
   733 		newbucket->base = bucket->base+size;
   734 		newbucket->size = extra;
   735 		newbucket->next = bucket->next;
   736 		if ( bucket->next ) {
   737 			bucket->next->prev = newbucket;
   738 		}
   739 		bucket->next = newbucket;
   740 	}
   741 
   742 	/* Set the current bucket values and return it! */
   743 	bucket->used = 1;
   744 	bucket->size = size;
   745 	bucket->dirty = 0;
   746 #ifdef DGA_DEBUG
   747 	fprintf(stderr, "Allocated %d bytes at %p\n", bucket->size, bucket->base);
   748 #endif
   749 	surfaces_memleft -= size;
   750 	surface->flags |= SDL_HWSURFACE;
   751 	surface->pixels = bucket->base;
   752 	surface->hwdata = (struct private_hwdata *)bucket;
   753 done:
   754 	UNLOCK_DISPLAY();
   755 	return(retval);
   756 }
   757 static void DGA_FreeHWSurface(_THIS, SDL_Surface *surface)
   758 {
   759 	vidmem_bucket *bucket, *freeable;
   760 
   761 	/* Look for the bucket in the current list */
   762 	for ( bucket=&surfaces; bucket; bucket=bucket->next ) {
   763 		if ( bucket == (vidmem_bucket *)surface->hwdata ) {
   764 			break;
   765 		}
   766 	}
   767 	if ( bucket && bucket->used ) {
   768 		/* Add the memory back to the total */
   769 #ifdef DGA_DEBUG
   770 	printf("Freeing bucket of %d bytes\n", bucket->size);
   771 #endif
   772 		surfaces_memleft += bucket->size;
   773 
   774 		/* Can we merge the space with surrounding buckets? */
   775 		bucket->used = 0;
   776 		if ( bucket->next && ! bucket->next->used ) {
   777 #ifdef DGA_DEBUG
   778 	printf("Merging with next bucket, for %d total bytes\n", bucket->size+bucket->next->size);
   779 #endif
   780 			freeable = bucket->next;
   781 			bucket->size += bucket->next->size;
   782 			bucket->next = bucket->next->next;
   783 			if ( bucket->next ) {
   784 				bucket->next->prev = bucket;
   785 			}
   786 			SDL_free(freeable);
   787 		}
   788 		if ( bucket->prev && ! bucket->prev->used ) {
   789 #ifdef DGA_DEBUG
   790 	printf("Merging with previous bucket, for %d total bytes\n", bucket->prev->size+bucket->size);
   791 #endif
   792 			freeable = bucket;
   793 			bucket->prev->size += bucket->size;
   794 			bucket->prev->next = bucket->next;
   795 			if ( bucket->next ) {
   796 				bucket->next->prev = bucket->prev;
   797 			}
   798 			SDL_free(freeable);
   799 		}
   800 	}
   801 	surface->pixels = NULL;
   802 	surface->hwdata = NULL;
   803 }
   804 
   805 static __inline__ void DGA_dst_to_xy(_THIS, SDL_Surface *dst, int *x, int *y)
   806 {
   807 	*x = (long)((Uint8 *)dst->pixels - memory_base)%memory_pitch;
   808 	*y = (long)((Uint8 *)dst->pixels - memory_base)/memory_pitch;
   809 }
   810 
   811 static int DGA_FillHWRect(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color)
   812 {
   813 	int x, y;
   814 	unsigned int w, h;
   815 
   816 	/* Don't fill the visible part of the screen, wait until flipped */
   817 	LOCK_DISPLAY();
   818 	if ( was_flipped && (dst == this->screen) ) {
   819 		while ( SDL_NAME(XDGAGetViewportStatus)(DGA_Display, DGA_Screen) )
   820 			/* Keep waiting for the hardware ... */ ;
   821 		was_flipped = 0;
   822 	}
   823 	DGA_dst_to_xy(this, dst, &x, &y);
   824 	x += rect->x;
   825 	y += rect->y;
   826 	w = rect->w;
   827 	h = rect->h;
   828 #if 0
   829   printf("Hardware accelerated rectangle fill: %dx%d at %d,%d\n", w, h, x, y);
   830 #endif
   831 	SDL_NAME(XDGAFillRectangle)(DGA_Display, DGA_Screen, x, y, w, h, color);
   832 	if ( !(this->screen->flags & SDL_DOUBLEBUF) ) {
   833 		XFlush(DGA_Display);
   834 	}
   835 	DGA_AddBusySurface(dst);
   836 	UNLOCK_DISPLAY();
   837 	return(0);
   838 }
   839 
   840 static int HWAccelBlit(SDL_Surface *src, SDL_Rect *srcrect,
   841                        SDL_Surface *dst, SDL_Rect *dstrect)
   842 {
   843 	SDL_VideoDevice *this;
   844 	int srcx, srcy;
   845 	int dstx, dsty;
   846 	unsigned int w, h;
   847 
   848 	this = current_video;
   849 	/* Don't blit to the visible part of the screen, wait until flipped */
   850 	LOCK_DISPLAY();
   851 	if ( was_flipped && (dst == this->screen) ) {
   852 		while ( SDL_NAME(XDGAGetViewportStatus)(DGA_Display, DGA_Screen) )
   853 			/* Keep waiting for the hardware ... */ ;
   854 		was_flipped = 0;
   855 	}
   856 	DGA_dst_to_xy(this, src, &srcx, &srcy);
   857 	srcx += srcrect->x;
   858 	srcy += srcrect->y;
   859 	DGA_dst_to_xy(this, dst, &dstx, &dsty);
   860 	dstx += dstrect->x;
   861 	dsty += dstrect->y;
   862 	w = srcrect->w;
   863 	h = srcrect->h;
   864 #if 0
   865   printf("Blitting %dx%d from %d,%d to %d,%d\n", w, h, srcx, srcy, dstx, dsty);
   866 #endif
   867 	if ( (src->flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) {
   868 		SDL_NAME(XDGACopyTransparentArea)(DGA_Display, DGA_Screen,
   869 			srcx, srcy, w, h, dstx, dsty, src->format->colorkey);
   870 	} else {
   871 		SDL_NAME(XDGACopyArea)(DGA_Display, DGA_Screen,
   872 			srcx, srcy, w, h, dstx, dsty);
   873 	}
   874 	if ( !(this->screen->flags & SDL_DOUBLEBUF) ) {
   875 		XFlush(DGA_Display);
   876 	}
   877 	DGA_AddBusySurface(src);
   878 	DGA_AddBusySurface(dst);
   879 	UNLOCK_DISPLAY();
   880 	return(0);
   881 }
   882 
   883 static int DGA_CheckHWBlit(_THIS, SDL_Surface *src, SDL_Surface *dst)
   884 {
   885 	int accelerated;
   886 
   887 	/* Set initial acceleration on */
   888 	src->flags |= SDL_HWACCEL;
   889 
   890 	/* Set the surface attributes */
   891 	if ( (src->flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
   892 		if ( ! this->info.blit_hw_A ) {
   893 			src->flags &= ~SDL_HWACCEL;
   894 		}
   895 	}
   896 	if ( (src->flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) {
   897 		if ( ! this->info.blit_hw_CC ) {
   898 			src->flags &= ~SDL_HWACCEL;
   899 		}
   900 	}
   901 
   902 	/* Check to see if final surface blit is accelerated */
   903 	accelerated = !!(src->flags & SDL_HWACCEL);
   904 	if ( accelerated ) {
   905 		src->map->hw_blit = HWAccelBlit;
   906 	}
   907 	return(accelerated);
   908 }
   909 
   910 static __inline__ void DGA_WaitFlip(_THIS)
   911 {
   912 	if ( was_flipped ) {
   913 		while ( SDL_NAME(XDGAGetViewportStatus)(DGA_Display, DGA_Screen) )
   914 			/* Keep waiting for the hardware ... */ ;
   915 		was_flipped = 0;
   916 	}
   917 }
   918 
   919 static int DGA_LockHWSurface(_THIS, SDL_Surface *surface)
   920 {
   921 	if ( surface == this->screen ) {
   922 		SDL_mutexP(hw_lock);
   923 		LOCK_DISPLAY();
   924 		if ( DGA_IsSurfaceBusy(surface) ) {
   925 			DGA_WaitBusySurfaces(this);
   926 		}
   927 		DGA_WaitFlip(this);
   928 		UNLOCK_DISPLAY();
   929 	} else {
   930 		if ( DGA_IsSurfaceBusy(surface) ) {
   931 			LOCK_DISPLAY();
   932 			DGA_WaitBusySurfaces(this);
   933 			UNLOCK_DISPLAY();
   934 		}
   935 	}
   936 	return(0);
   937 }
   938 static void DGA_UnlockHWSurface(_THIS, SDL_Surface *surface)
   939 {
   940 	if ( surface == this->screen ) {
   941 		SDL_mutexV(hw_lock);
   942 	}
   943 }
   944 
   945 static int DGA_FlipHWSurface(_THIS, SDL_Surface *surface)
   946 {
   947 	/* Wait for vertical retrace and then flip display */
   948 	LOCK_DISPLAY();
   949 	if ( DGA_IsSurfaceBusy(this->screen) ) {
   950 		DGA_WaitBusySurfaces(this);
   951 	}
   952 	DGA_WaitFlip(this);
   953 	SDL_NAME(XDGASetViewport)(DGA_Display, DGA_Screen,
   954 	                0, flip_yoffset[flip_page], XDGAFlipRetrace);
   955 	XFlush(DGA_Display);
   956 	UNLOCK_DISPLAY();
   957 	was_flipped = 1;
   958 	flip_page = !flip_page;
   959 
   960 	surface->pixels = flip_address[flip_page];
   961 	return(0);
   962 }
   963 
   964 static void DGA_DirectUpdate(_THIS, int numrects, SDL_Rect *rects)
   965 {
   966 	/* The application is already updating the visible video memory */
   967 	return;
   968 }
   969 
   970 static int DGA_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
   971 {
   972         int i;
   973 	XColor  *xcmap;
   974 
   975 	/* This happens on initialization */
   976 	if ( ! DGA_colormap ) {
   977 		return(0);
   978 	}
   979 	xcmap = SDL_stack_alloc(XColor, ncolors);
   980 	for ( i=0; i<ncolors; ++i ) {
   981 		xcmap[i].pixel = firstcolor + i;
   982 		xcmap[i].red   = (colors[i].r<<8)|colors[i].r;
   983 		xcmap[i].green = (colors[i].g<<8)|colors[i].g;
   984 		xcmap[i].blue  = (colors[i].b<<8)|colors[i].b;
   985 		xcmap[i].flags = (DoRed|DoGreen|DoBlue);
   986 	}
   987 	LOCK_DISPLAY();
   988 	XStoreColors(DGA_Display, DGA_colormap, xcmap, ncolors);
   989 	XSync(DGA_Display, False);
   990 	UNLOCK_DISPLAY();
   991 	SDL_stack_free(xcmap);
   992 
   993 	/* That was easy. :) */
   994 	return(1);
   995 }
   996 
   997 int DGA_SetGammaRamp(_THIS, Uint16 *ramp)
   998 {
   999 	int i, ncolors;
  1000 	XColor xcmap[256];
  1001 
  1002 	/* See if actually setting the gamma is supported */
  1003 	if ( DGA_visualClass != DirectColor ) {
  1004 	    SDL_SetError("Gamma correction not supported on this visual");
  1005 	    return(-1);
  1006 	}
  1007 
  1008 	/* Calculate the appropriate palette for the given gamma ramp */
  1009 	if ( this->screen->format->BitsPerPixel <= 16 ) {
  1010 		ncolors = 64; /* Is this right? */
  1011 	} else {
  1012 		ncolors = 256;
  1013 	}
  1014 	for ( i=0; i<ncolors; ++i ) {
  1015 		Uint8 c = (256 * i / ncolors);
  1016 		xcmap[i].pixel = SDL_MapRGB(this->screen->format, c, c, c);
  1017 		xcmap[i].red   = ramp[0*256+c];
  1018 		xcmap[i].green = ramp[1*256+c];
  1019 		xcmap[i].blue  = ramp[2*256+c];
  1020 		xcmap[i].flags = (DoRed|DoGreen|DoBlue);
  1021 	}
  1022 	LOCK_DISPLAY();
  1023 	XStoreColors(DGA_Display, DGA_colormap, xcmap, ncolors);
  1024 	XSync(DGA_Display, False);
  1025 	UNLOCK_DISPLAY();
  1026 	return(0);
  1027 }
  1028 
  1029 void DGA_VideoQuit(_THIS)
  1030 {
  1031 	int i, j;
  1032 
  1033 	if ( DGA_Display ) {
  1034 		/* Free colormap, if necessary */
  1035 		if ( DGA_colormap ) {
  1036 			XFreeColormap(DGA_Display, DGA_colormap);
  1037 			DGA_colormap = 0;
  1038 		}
  1039 
  1040 		/* Unmap memory and reset video mode */
  1041 		SDL_NAME(XDGACloseFramebuffer)(DGA_Display, DGA_Screen);
  1042 		if ( this->screen ) {
  1043 			/* Tell SDL not to free the pixels */
  1044 			this->screen->pixels = NULL;
  1045 		}
  1046 		SDL_NAME(XDGASetMode)(DGA_Display, DGA_Screen, 0);
  1047 
  1048 		/* Clear the lock mutex */
  1049 		if ( hw_lock != NULL ) {
  1050 			SDL_DestroyMutex(hw_lock);
  1051 			hw_lock = NULL;
  1052 		}
  1053 #ifdef LOCK_DGA_DISPLAY
  1054 		if ( event_lock != NULL ) {
  1055 			SDL_DestroyMutex(event_lock);
  1056 			event_lock = NULL;
  1057 		}
  1058 #endif /* LOCK_DGA_DISPLAY */
  1059 
  1060 		/* Clean up defined video modes */
  1061 		for ( i=0; i<NUM_MODELISTS; ++i ) {
  1062 			if ( SDL_modelist[i] != NULL ) {
  1063 				for ( j=0; SDL_modelist[i][j]; ++j ) {
  1064 					SDL_free(SDL_modelist[i][j]);
  1065 				}
  1066 				SDL_free(SDL_modelist[i]);
  1067 				SDL_modelist[i] = NULL;
  1068 			}
  1069 		}
  1070 
  1071 		/* Clean up the memory bucket list */
  1072 		DGA_FreeHWSurfaces(this);
  1073 
  1074 		/* Restore DPMS and screensaver settings */
  1075 		X11_RestoreScreenSaver(DGA_Display, screensaver_timeout, dpms_enabled);
  1076 
  1077 		/* Close up the display */
  1078 		XCloseDisplay(DGA_Display);
  1079 	}
  1080 }