SDL_dgavideo.c
上传用户:sun1608
上传日期:2007-02-02
资源大小:6116k
文件大小:29k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

Visual C++

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