Mercurial > sdl-ios-xcode
view src/video/x11/SDL_x11image.c @ 1895:c121d94672cb
SDL 1.2 is moving to a branch, and SDL 1.3 is becoming the head.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Mon, 10 Jul 2006 21:04:37 +0000 |
parents | 3ba88cb7eb1b |
children |
line wrap: on
line source
/* SDL - Simple DirectMedia Layer Copyright (C) 1997-2006 Sam Lantinga This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Sam Lantinga slouken@libsdl.org */ #include "SDL_config.h" #include <stdio.h> #include <unistd.h> #include "SDL_endian.h" #include "../../events/SDL_events_c.h" #include "SDL_x11image_c.h" #ifndef NO_SHARED_MEMORY /* Shared memory error handler routine */ static int shm_error; static int (*X_handler) (Display *, XErrorEvent *) = NULL; static int shm_errhandler(Display * d, XErrorEvent * e) { if (e->error_code == BadAccess) { shm_error = True; return (0); } else return (X_handler(d, e)); } static void try_mitshm(_THIS, SDL_Surface * screen) { /* Dynamic X11 may not have SHM entry points on this box. */ if ((use_mitshm) && (!SDL_X11_HAVE_SHM)) use_mitshm = 0; if (!use_mitshm) return; shminfo.shmid = shmget(IPC_PRIVATE, screen->h * screen->pitch, IPC_CREAT | 0777); if (shminfo.shmid >= 0) { shminfo.shmaddr = (char *) shmat(shminfo.shmid, 0, 0); shminfo.readOnly = False; if (shminfo.shmaddr != (char *) -1) { shm_error = False; X_handler = XSetErrorHandler(shm_errhandler); XShmAttach(SDL_Display, &shminfo); XSync(SDL_Display, True); XSetErrorHandler(X_handler); if (shm_error) shmdt(shminfo.shmaddr); } else { shm_error = True; } shmctl(shminfo.shmid, IPC_RMID, NULL); } else { shm_error = True; } if (shm_error) use_mitshm = 0; if (use_mitshm) screen->pixels = shminfo.shmaddr; } #endif /* ! NO_SHARED_MEMORY */ /* Various screen update functions available */ static void X11_NormalUpdate(_THIS, int numrects, SDL_Rect * rects); static void X11_MITSHMUpdate(_THIS, int numrects, SDL_Rect * rects); int X11_SetupImage(_THIS, SDL_Surface * screen) { #ifndef NO_SHARED_MEMORY try_mitshm(this, screen); if (use_mitshm) { SDL_Ximage = XShmCreateImage(SDL_Display, SDL_Visual, this->hidden->depth, ZPixmap, shminfo.shmaddr, &shminfo, screen->w, screen->h); if (!SDL_Ximage) { XShmDetach(SDL_Display, &shminfo); XSync(SDL_Display, False); shmdt(shminfo.shmaddr); screen->pixels = NULL; goto error; } this->UpdateRects = X11_MITSHMUpdate; } if (!use_mitshm) #endif /* not NO_SHARED_MEMORY */ { int bpp; screen->pixels = SDL_malloc(screen->h * screen->pitch); if (screen->pixels == NULL) { SDL_OutOfMemory(); return -1; } bpp = screen->format->BytesPerPixel; SDL_Ximage = XCreateImage(SDL_Display, SDL_Visual, this->hidden->depth, ZPixmap, 0, (char *) screen->pixels, screen->w, screen->h, 32, 0); if (SDL_Ximage == NULL) goto error; /* XPutImage will convert byte sex automatically */ SDL_Ximage->byte_order = (SDL_BYTEORDER == SDL_BIG_ENDIAN) ? MSBFirst : LSBFirst; this->UpdateRects = X11_NormalUpdate; } screen->pitch = SDL_Ximage->bytes_per_line; return (0); error: SDL_SetError("Couldn't create XImage"); return 1; } void X11_DestroyImage(_THIS, SDL_Surface * screen) { if (SDL_Ximage) { XDestroyImage(SDL_Ximage); #ifndef NO_SHARED_MEMORY if (use_mitshm) { XShmDetach(SDL_Display, &shminfo); XSync(SDL_Display, False); shmdt(shminfo.shmaddr); } #endif /* ! NO_SHARED_MEMORY */ SDL_Ximage = NULL; } if (screen) { screen->pixels = NULL; } } /* Determine the number of CPUs in the system */ static int num_CPU(void) { static int num_cpus = 0; if (!num_cpus) { #if defined(__LINUX__) char line[BUFSIZ]; FILE *pstat = fopen("/proc/stat", "r"); if (pstat) { while (fgets(line, sizeof(line), pstat)) { if (SDL_memcmp(line, "cpu", 3) == 0 && line[3] != ' ') { ++num_cpus; } } fclose(pstat); } #elif defined(__IRIX__) num_cpus = sysconf(_SC_NPROC_ONLN); #elif defined(_SC_NPROCESSORS_ONLN) /* number of processors online (SVR4.0MP compliant machines) */ num_cpus = sysconf(_SC_NPROCESSORS_ONLN); #elif defined(_SC_NPROCESSORS_CONF) /* number of processors configured (SVR4.0MP compliant machines) */ num_cpus = sysconf(_SC_NPROCESSORS_CONF); #endif if (num_cpus <= 0) { num_cpus = 1; } } return num_cpus; } int X11_ResizeImage(_THIS, SDL_Surface * screen, Uint32 flags) { int retval; X11_DestroyImage(this, screen); if (flags & SDL_INTERNALOPENGL) { /* No image when using GL */ retval = 0; } else { retval = X11_SetupImage(this, screen); /* We support asynchronous blitting on the display */ if (flags & SDL_ASYNCBLIT) { /* This is actually slower on single-CPU systems, probably because of CPU contention between the X server and the application. Note: Is this still true with XFree86 4.0? */ if (num_CPU() > 1) { screen->flags |= SDL_ASYNCBLIT; } } } return (retval); } /* We don't actually allow hardware surfaces other than the main one */ int X11_AllocHWSurface(_THIS, SDL_Surface * surface) { return (-1); } void X11_FreeHWSurface(_THIS, SDL_Surface * surface) { return; } int X11_LockHWSurface(_THIS, SDL_Surface * surface) { if ((surface == SDL_VideoSurface) && blit_queued) { XSync(GFX_Display, False); blit_queued = 0; } return (0); } void X11_UnlockHWSurface(_THIS, SDL_Surface * surface) { return; } int X11_FlipHWSurface(_THIS, SDL_Surface * surface) { return (0); } static void X11_NormalUpdate(_THIS, int numrects, SDL_Rect * rects) { int i; for (i = 0; i < numrects; ++i) { if (rects[i].w == 0 || rects[i].h == 0) { /* Clipped? */ continue; } XPutImage(GFX_Display, SDL_Window, SDL_GC, SDL_Ximage, rects[i].x, rects[i].y, rects[i].x, rects[i].y, rects[i].w, rects[i].h); } if (SDL_VideoSurface->flags & SDL_ASYNCBLIT) { XFlush(GFX_Display); blit_queued = 1; } else { XSync(GFX_Display, False); } } static void X11_MITSHMUpdate(_THIS, int numrects, SDL_Rect * rects) { #ifndef NO_SHARED_MEMORY int i; for (i = 0; i < numrects; ++i) { if (rects[i].w == 0 || rects[i].h == 0) { /* Clipped? */ continue; } XShmPutImage(GFX_Display, SDL_Window, SDL_GC, SDL_Ximage, rects[i].x, rects[i].y, rects[i].x, rects[i].y, rects[i].w, rects[i].h, False); } if (SDL_VideoSurface->flags & SDL_ASYNCBLIT) { XFlush(GFX_Display); blit_queued = 1; } else { XSync(GFX_Display, False); } #endif /* ! NO_SHARED_MEMORY */ } /* There's a problem with the automatic refreshing of the display. Even though the XVideo code uses the GFX_Display to update the video memory, it appears that updating the window asynchronously from a different thread will cause "blackouts" of the window. This is a sort of a hacked workaround for the problem. */ static int enable_autorefresh = 1; void X11_DisableAutoRefresh(_THIS) { --enable_autorefresh; } void X11_EnableAutoRefresh(_THIS) { ++enable_autorefresh; } void X11_RefreshDisplay(_THIS) { /* Don't refresh a display that doesn't have an image (like GL) Instead, post an expose event so the application can refresh. */ if (!SDL_Ximage || (enable_autorefresh <= 0)) { SDL_PrivateExpose(); return; } #ifndef NO_SHARED_MEMORY if (this->UpdateRects == X11_MITSHMUpdate) { XShmPutImage(SDL_Display, SDL_Window, SDL_GC, SDL_Ximage, 0, 0, SDL_CurrentWindow.offset_x, SDL_CurrentWindow.offset_y, SDL_CurrentDisplay.current_mode.w, SDL_CurrentDisplay.current_mode.h, False); } else #endif /* ! NO_SHARED_MEMORY */ { XPutImage(SDL_Display, SDL_Window, SDL_GC, SDL_Ximage, 0, 0, SDL_CurrentWindow.offset_x, SDL_CurrentWindow.offset_y, SDL_CurrentDisplay.current_mode.w, SDL_CurrentDisplay.current_mode.h); } XSync(SDL_Display, False); } /* vi: set ts=4 sw=4 expandtab: */