src/video/dga/SDL_dgavideo.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. DGA_Available
  2. DGA_DeleteDevice
  3. DGA_CreateDevice
  4. DGA_AddMode
  5. get_video_size
  6. PrintMode
  7. cmpmodes
  8. UpdateHWInfo
  9. DGA_VideoInit
  10. DGA_ListModes
  11. DGA_SetVideoMode
  12. DGA_DumpHWSurfaces
  13. DGA_InitHWSurfaces
  14. DGA_FreeHWSurfaces
  15. DGA_AllocHWSurface
  16. DGA_FreeHWSurface
  17. dst_to_xy
  18. DGA_FillHWRect
  19. HWAccelBlit
  20. DGA_CheckHWBlit
  21. DGA_WaitHardware
  22. DGA_LockHWSurface
  23. DGA_UnlockHWSurface
  24. DGA_FlipHWSurface
  25. DGA_DirectUpdate
  26. DGA_SetColors
  27. DGA_SetGammaRamp
  28. DGA_VideoQuit

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

/* [<][>][^][v][top][bottom][index][help] */