src/video/x11/SDL_x11image.c

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

FUNCTIONS

This source file includes following functions.
  1. shm_errhandler
  2. X11_SetupImage
  3. X11_DestroyImage
  4. num_CPU
  5. X11_ResizeImage
  6. X11_AllocHWSurface
  7. X11_FreeHWSurface
  8. X11_LockHWSurface
  9. X11_UnlockHWSurface
  10. X11_FlipHWSurface
  11. X11_SwapAllPixels
  12. X11_SwapPixels
  13. X11_NormalUpdate
  14. X11_MITSHMUpdate
  15. X11_DisableAutoRefresh
  16. X11_EnableAutoRefresh
  17. X11_RefreshDisplay

   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_x11image.c,v 1.1.2.18 2001/02/20 19:53:22 hercules Exp $";
  26 #endif
  27 
  28 #include <stdlib.h>
  29 
  30 #include "SDL_error.h"
  31 #include "SDL_endian.h"
  32 #include "SDL_x11image_c.h"
  33 
  34 #if defined(__USLC__)
  35 #ifdef HAVE_KSTAT
  36 #undef HAVE_KSTAT
  37 #endif
  38 #include <unistd.h>
  39 #endif
  40 
  41 #ifdef HAVE_KSTAT
  42 #include <kstat.h>
  43 #endif
  44 
  45 #ifndef NO_SHARED_MEMORY
  46 
  47 /* Shared memory information */
  48 extern int XShmQueryExtension(Display *dpy);    /* Not in X11 headers */
  49 
  50 /* Shared memory error handler routine */
  51 static int shm_error;
  52 static int (*X_handler)(Display *, XErrorEvent *) = NULL;
  53 static int shm_errhandler(Display *d, XErrorEvent *e)
     /* [<][>][^][v][top][bottom][index][help] */
  54 {
  55         if ( e->error_code == BadAccess ) {
  56                 ++shm_error;
  57                 return(0);
  58         } else
  59                 return(X_handler(d,e));
  60 }
  61 #endif /* ! NO_SHARED_MEMORY */
  62 
  63 /* Various screen update functions available */
  64 static void X11_NormalUpdate(_THIS, int numrects, SDL_Rect *rects);
  65 static void X11_MITSHMUpdate(_THIS, int numrects, SDL_Rect *rects);
  66 
  67 int X11_SetupImage(_THIS, SDL_Surface *screen)
     /* [<][>][^][v][top][bottom][index][help] */
  68 {
  69 #ifdef NO_SHARED_MEMORY
  70         screen->pixels = malloc(screen->h*screen->pitch);
  71 #else
  72         /* Allocate shared memory if possible */
  73         if ( use_mitshm ) {
  74                 shminfo.shmid = shmget(IPC_PRIVATE, screen->h*screen->pitch,
  75                                                                 IPC_CREAT|0777);
  76                 if ( shminfo.shmid >= 0 ) {
  77                         shminfo.shmaddr = (char *)shmat(shminfo.shmid, 0, 0);
  78                         shminfo.readOnly = False;
  79                         if ( shminfo.shmaddr != (char *)-1 ) {
  80                                 shm_error = False;
  81                                 X_handler = XSetErrorHandler(shm_errhandler);
  82                                 XShmAttach(SDL_Display, &shminfo);
  83                                 XSync(SDL_Display, True);
  84                                 XSetErrorHandler(X_handler);
  85                                 if ( shm_error == True )
  86                                         shmdt(shminfo.shmaddr);
  87                         } else {
  88                                 shm_error = True;
  89                         }
  90                         shmctl(shminfo.shmid, IPC_RMID, NULL);
  91                 } else {
  92                         shm_error = True;
  93                 }
  94                 if ( shm_error == True )
  95                         use_mitshm = 0;
  96         }
  97         if ( use_mitshm ) {
  98                 screen->pixels = shminfo.shmaddr;
  99         } else {
 100                 screen->pixels = malloc(screen->h*screen->pitch);
 101         }
 102 #endif /* NO_SHARED_MEMORY */
 103         if ( screen->pixels == NULL ) {
 104                 SDL_OutOfMemory();
 105                 return(-1);
 106         }
 107 
 108 #ifdef NO_SHARED_MEMORY
 109         {
 110                 int bpp = screen->format->BytesPerPixel;
 111                 SDL_Ximage = XCreateImage(SDL_Display, SDL_Visual,
 112                                           this->hidden->depth, ZPixmap, 0,
 113                                           (char *)screen->pixels, 
 114                                           screen->w, screen->h,
 115                                           (bpp == 3) ? 32 : bpp * 8,
 116                                           0);
 117         }
 118 #else
 119         if ( use_mitshm ) {
 120                 SDL_Ximage = XShmCreateImage(SDL_Display, SDL_Visual,
 121                                              this->hidden->depth, ZPixmap,
 122                                              shminfo.shmaddr, &shminfo, 
 123                                              screen->w, screen->h);
 124         } else {
 125                 int bpp = screen->format->BytesPerPixel;
 126                 SDL_Ximage = XCreateImage(SDL_Display, SDL_Visual,
 127                                           this->hidden->depth, ZPixmap, 0,
 128                                           (char *)screen->pixels, 
 129                                           screen->w, screen->h,
 130                                           (bpp == 3) ? 32 : bpp * 8,
 131                                           0);
 132         }
 133 #endif /* NO_SHARED_MEMORY */
 134         if ( SDL_Ximage == NULL ) {
 135                 SDL_SetError("Couldn't create XImage");
 136 #ifndef NO_SHARED_MEMORY
 137                 if ( use_mitshm ) {
 138                         XShmDetach(SDL_Display, &shminfo);
 139                         XSync(SDL_Display, False);
 140                         shmdt(shminfo.shmaddr);
 141                         screen->pixels = NULL;
 142                 }
 143 #endif /* ! NO_SHARED_MEMORY */
 144                 return(-1);
 145         }
 146         screen->pitch = SDL_Ximage->bytes_per_line;
 147 
 148         /* Determine what blit function to use */
 149 #ifdef NO_SHARED_MEMORY
 150         this->UpdateRects = X11_NormalUpdate;
 151 #else
 152         if ( use_mitshm ) {
 153                 this->UpdateRects = X11_MITSHMUpdate;
 154         } else {
 155                 this->UpdateRects = X11_NormalUpdate;
 156         }
 157 #endif
 158         return(0);
 159 }
 160 
 161 void X11_DestroyImage(_THIS, SDL_Surface *screen)
     /* [<][>][^][v][top][bottom][index][help] */
 162 {
 163         if ( SDL_Ximage ) {
 164                 XDestroyImage(SDL_Ximage);
 165 #ifndef NO_SHARED_MEMORY
 166                 if ( use_mitshm ) {
 167                         XShmDetach(SDL_Display, &shminfo);
 168                         XSync(SDL_Display, False);
 169                         shmdt(shminfo.shmaddr);
 170                 }
 171 #endif /* ! NO_SHARED_MEMORY */
 172                 SDL_Ximage = NULL;
 173         }
 174         if ( screen ) {
 175                 screen->pixels = NULL;
 176         }
 177 }
 178 
 179 /* This is a hack to see whether this system has more than 1 CPU */
 180 static int num_CPU(void)
     /* [<][>][^][v][top][bottom][index][help] */
 181 {
 182        static int num_cpus = 0;
 183 
 184        if(!num_cpus) {
 185 #ifdef linux
 186            char line[BUFSIZ];
 187            FILE *pstat = fopen("/proc/stat", "r");
 188            if ( pstat ) {
 189                while ( fgets(line, sizeof(line), pstat) ) {
 190                    if (memcmp(line, "cpu", 3) == 0 && line[3] != ' ') {
 191                        ++num_cpus;
 192                    }
 193                }
 194                fclose(pstat);
 195            }
 196 #elif defined(HAVE_KSTAT)
 197            kstat_ctl_t *kc = kstat_open();
 198            kstat_t *ks;
 199            kstat_named_t *kn;
 200            if(kc) {
 201                if((ks = kstat_lookup(kc, "unix", -1, "system_misc"))
 202                   && kstat_read(kc, ks, NULL) != -1
 203                   && (kn = kstat_data_lookup(ks, "ncpus")))
 204 #ifdef KSTAT_DATA_UINT32
 205                    num_cpus = kn->value.ui32;
 206 #else
 207                    num_cpus = kn->value.ul; /* needed in solaris <2.6 */
 208 #endif
 209                kstat_close(kc);
 210            }
 211 #elif defined(__USLC__)
 212            num_cpus = (int)sysconf(_SC_NPROCESSORS_CONF);
 213 #endif
 214            if ( num_cpus <= 0 ) {
 215                num_cpus = 1;
 216            }
 217        }
 218        return num_cpus;
 219 }
 220 
 221 int X11_ResizeImage(_THIS, SDL_Surface *screen, Uint32 flags)
     /* [<][>][^][v][top][bottom][index][help] */
 222 {
 223         int retval;
 224 
 225         X11_DestroyImage(this, screen);
 226         if ( flags & SDL_OPENGL ) {  /* No image when using GL */
 227                 retval = 0;
 228         } else {
 229                 retval = X11_SetupImage(this, screen);
 230                 /* We support asynchronous blitting on the display */
 231                 if ( flags & SDL_ASYNCBLIT ) {
 232                         /* This is actually slower on single-CPU systems,
 233                            probably because of CPU contention between the
 234                            X server and the application.
 235                            Note: Is this still true with XFree86 4.0?
 236                         */
 237                         if ( num_CPU() > 1 ) {
 238                                 screen->flags |= SDL_ASYNCBLIT;
 239                         }
 240                 }
 241         }
 242         return(retval);
 243 }
 244 
 245 /* We don't actually allow hardware surfaces other than the main one */
 246 int X11_AllocHWSurface(_THIS, SDL_Surface *surface)
     /* [<][>][^][v][top][bottom][index][help] */
 247 {
 248         return(-1);
 249 }
 250 void X11_FreeHWSurface(_THIS, SDL_Surface *surface)
     /* [<][>][^][v][top][bottom][index][help] */
 251 {
 252         return;
 253 }
 254 
 255 int X11_LockHWSurface(_THIS, SDL_Surface *surface)
     /* [<][>][^][v][top][bottom][index][help] */
 256 {
 257         if ( (surface == SDL_VideoSurface) && blit_queued ) {
 258                 XSync(GFX_Display, False);
 259                 blit_queued = 0;
 260         }
 261         return(0);
 262 }
 263 void X11_UnlockHWSurface(_THIS, SDL_Surface *surface)
     /* [<][>][^][v][top][bottom][index][help] */
 264 {
 265         return;
 266 }
 267 
 268 int X11_FlipHWSurface(_THIS, SDL_Surface *surface)
     /* [<][>][^][v][top][bottom][index][help] */
 269 {
 270         return(0);
 271 }
 272 
 273 /* Byte-swap the pixels in the display image */
 274 static void X11_SwapAllPixels(SDL_Surface *screen)
     /* [<][>][^][v][top][bottom][index][help] */
 275 {
 276         int x, y;
 277 
 278         switch (screen->format->BytesPerPixel) {
 279             case 2: {
 280                 Uint16 *spot;
 281                 for ( y=0; y<screen->h; ++y ) {
 282                         spot = (Uint16 *) ((Uint8 *)screen->pixels +
 283                                                 y * screen->pitch);
 284                         for ( x=0; x<screen->w; ++x, ++spot ) {
 285                                 *spot = SDL_Swap16(*spot);
 286                         }
 287                 }
 288             }
 289             break;
 290 
 291             case 4: {
 292                 Uint32 *spot;
 293                 for ( y=0; y<screen->h; ++y ) {
 294                         spot = (Uint32 *) ((Uint8 *)screen->pixels +
 295                                                 y * screen->pitch);
 296                         for ( x=0; x<screen->w; ++x, ++spot ) {
 297                                 *spot = SDL_Swap32(*spot);
 298                         }
 299                 }
 300             }
 301             break;
 302 
 303             default:
 304                 /* should never get here */
 305                 break;
 306         }
 307 }
 308 static void X11_SwapPixels(SDL_Surface *screen, SDL_Rect *rect)
     /* [<][>][^][v][top][bottom][index][help] */
 309 {
 310         int x, minx, maxx;
 311         int y, miny, maxy;
 312 
 313         switch (screen->format->BytesPerPixel) {
 314             case 2: {
 315                 Uint16 *spot;
 316                 minx = rect->x;
 317                 maxx = rect->x + rect->w;
 318                 miny = rect->y;
 319                 maxy = rect->y + rect->h;
 320                 for ( y=miny; y<maxy; ++y ) {
 321                     spot = (Uint16 *) ((Uint8 *)screen->pixels +
 322                                        y * screen->pitch + minx * 2);
 323                     for ( x=minx; x<maxx; ++x, ++spot ) {
 324                         *spot = SDL_Swap16(*spot);
 325                     }
 326                 }
 327             }
 328             break;
 329 
 330             case 4: {
 331                 Uint32 *spot;
 332                 minx = rect->x;
 333                 maxx = rect->x + rect->w;
 334                 miny = rect->y;
 335                 maxy = rect->y + rect->h;
 336                 for ( y=miny; y<maxy; ++y ) {
 337                     spot = (Uint32 *) ((Uint8 *)screen->pixels +
 338                                        y * screen->pitch + minx * 4);
 339                     for ( x=minx; x<maxx; ++x, ++spot ) {
 340                         *spot = SDL_Swap32(*spot);
 341                     }
 342                 }
 343             }
 344             break;
 345 
 346             default:
 347                 /* should never get here */
 348                 break;
 349         }
 350 }
 351 
 352 static void X11_NormalUpdate(_THIS, int numrects, SDL_Rect *rects)
     /* [<][>][^][v][top][bottom][index][help] */
 353 {
 354         int i;
 355 
 356         /* Check for endian-swapped X server, swap if necessary (VERY slow!) */
 357         if ( swap_pixels &&
 358              ((this->screen->format->BytesPerPixel%2) == 0) ) {
 359                 for ( i=0; i<numrects; ++i ) {
 360                         if ( ! rects[i].w ) { /* Clipped? */
 361                                 continue;
 362                         }
 363                         X11_SwapPixels(this->screen, rects + i);
 364                         XPutImage(GFX_Display, SDL_Window, SDL_GC, SDL_Ximage,
 365                                 rects[i].x, rects[i].y,
 366                                 rects[i].x, rects[i].y, rects[i].w, rects[i].h);
 367                         X11_SwapPixels(this->screen, rects + i);
 368                 }
 369         } else {
 370                 for ( i=0; i<numrects; ++i ) {
 371                         if ( ! rects[i].w ) { /* Clipped? */
 372                                 continue;
 373                         }
 374                         XPutImage(GFX_Display, SDL_Window, SDL_GC, SDL_Ximage,
 375                                 rects[i].x, rects[i].y,
 376                                 rects[i].x, rects[i].y, rects[i].w, rects[i].h);
 377                 }
 378         }
 379         if ( SDL_VideoSurface->flags & SDL_ASYNCBLIT ) {
 380                 XFlush(GFX_Display);
 381                 ++blit_queued;
 382         } else {
 383                 XSync(GFX_Display, False);
 384         }
 385 }
 386 
 387 static void X11_MITSHMUpdate(_THIS, int numrects, SDL_Rect *rects)
     /* [<][>][^][v][top][bottom][index][help] */
 388 {
 389 #ifndef NO_SHARED_MEMORY
 390         int i;
 391 
 392         for ( i=0; i<numrects; ++i ) {
 393                 if ( ! rects[i].w ) { /* Clipped? */
 394                         continue;
 395                 }
 396                 XShmPutImage(GFX_Display, SDL_Window, SDL_GC, SDL_Ximage,
 397                                 rects[i].x, rects[i].y,
 398                                 rects[i].x, rects[i].y, rects[i].w, rects[i].h,
 399                                                                         False);
 400         }
 401         if ( SDL_VideoSurface->flags & SDL_ASYNCBLIT ) {
 402                 XFlush(GFX_Display);
 403                 ++blit_queued;
 404         } else {
 405                 XSync(GFX_Display, False);
 406         }
 407 #endif /* ! NO_SHARED_MEMORY */
 408 }
 409 
 410 /* There's a problem with the automatic refreshing of the display.
 411    Even though the XVideo code uses the GFX_Display to update the
 412    video memory, it appears that updating the window asynchronously
 413    from a different thread will cause "blackouts" of the window.
 414    This is a sort of a hacked workaround for the problem.
 415 */
 416 static int enable_autorefresh = 1;
 417 
 418 void X11_DisableAutoRefresh(_THIS)
     /* [<][>][^][v][top][bottom][index][help] */
 419 {
 420         --enable_autorefresh;
 421 }
 422 
 423 void X11_EnableAutoRefresh(_THIS)
     /* [<][>][^][v][top][bottom][index][help] */
 424 {
 425         ++enable_autorefresh;
 426 }
 427 
 428 void X11_RefreshDisplay(_THIS)
     /* [<][>][^][v][top][bottom][index][help] */
 429 {
 430         /* Don't refresh a display that doesn't have an image (like GL) */
 431         if ( ! SDL_Ximage || (enable_autorefresh <= 0) ) {
 432                 return;
 433         }
 434 #ifndef NO_SHARED_MEMORY
 435         if ( this->UpdateRects == X11_MITSHMUpdate ) {
 436                 XShmPutImage(SDL_Display, SDL_Window, SDL_GC, SDL_Ximage,
 437                                 0, 0, 0, 0, this->screen->w, this->screen->h,
 438                                 False);
 439         } else {
 440 #else
 441         {
 442 #endif /* ! NO_SHARED_MEMORY */
 443                 /* Check for endian-swapped X server, swap if necessary */
 444                 if ( swap_pixels &&
 445                      ((this->screen->format->BytesPerPixel%2) == 0) ) {
 446                         X11_SwapAllPixels(this->screen);
 447                         XPutImage(SDL_Display, SDL_Window, SDL_GC, SDL_Ximage,
 448                                 0, 0, 0, 0, this->screen->w, this->screen->h);
 449                         X11_SwapAllPixels(this->screen);
 450                 } else {
 451                         XPutImage(SDL_Display, SDL_Window, SDL_GC, SDL_Ximage,
 452                                 0, 0, 0, 0, this->screen->w, this->screen->h);
 453                 }
 454         }
 455         XSync(SDL_Display, False);
 456 }

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