2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2009 Sam Lantinga
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "SDL_config.h"
27 #include "SDL_endian.h"
28 #include "../../events/SDL_events_c.h"
29 #include "SDL_x11image_c.h"
31 #ifndef NO_SHARED_MEMORY
33 /* Shared memory error handler routine */
35 static int (*X_handler)(Display *, XErrorEvent *) = NULL;
36 static int shm_errhandler(Display *d, XErrorEvent *e)
38 if ( e->error_code == BadAccess ) {
42 return(X_handler(d,e));
45 static void try_mitshm(_THIS, SDL_Surface *screen)
47 /* Dynamic X11 may not have SHM entry points on this box. */
48 if ((use_mitshm) && (!SDL_X11_HAVE_SHM))
53 shminfo.shmid = shmget(IPC_PRIVATE, screen->h*screen->pitch,
55 if ( shminfo.shmid >= 0 ) {
56 shminfo.shmaddr = (char *)shmat(shminfo.shmid, 0, 0);
57 shminfo.readOnly = False;
58 if ( shminfo.shmaddr != (char *)-1 ) {
60 X_handler = XSetErrorHandler(shm_errhandler);
61 XShmAttach(SDL_Display, &shminfo);
62 XSync(SDL_Display, True);
63 XSetErrorHandler(X_handler);
65 shmdt(shminfo.shmaddr);
69 shmctl(shminfo.shmid, IPC_RMID, NULL);
76 screen->pixels = shminfo.shmaddr;
78 #endif /* ! NO_SHARED_MEMORY */
80 /* Various screen update functions available */
81 static void X11_NormalUpdate(_THIS, int numrects, SDL_Rect *rects);
82 static void X11_MITSHMUpdate(_THIS, int numrects, SDL_Rect *rects);
84 int X11_SetupImage(_THIS, SDL_Surface *screen)
86 #ifndef NO_SHARED_MEMORY
87 try_mitshm(this, screen);
89 SDL_Ximage = XShmCreateImage(SDL_Display, SDL_Visual,
90 this->hidden->depth, ZPixmap,
91 shminfo.shmaddr, &shminfo,
92 screen->w, screen->h);
94 XShmDetach(SDL_Display, &shminfo);
95 XSync(SDL_Display, False);
96 shmdt(shminfo.shmaddr);
97 screen->pixels = NULL;
100 this->UpdateRects = X11_MITSHMUpdate;
103 #endif /* not NO_SHARED_MEMORY */
106 screen->pixels = SDL_malloc(screen->h*screen->pitch);
107 if ( screen->pixels == NULL ) {
111 bpp = screen->format->BytesPerPixel;
112 SDL_Ximage = XCreateImage(SDL_Display, SDL_Visual,
113 this->hidden->depth, ZPixmap, 0,
114 (char *)screen->pixels,
115 screen->w, screen->h,
117 if ( SDL_Ximage == NULL )
119 /* XPutImage will convert byte sex automatically */
120 SDL_Ximage->byte_order = (SDL_BYTEORDER == SDL_BIG_ENDIAN)
121 ? MSBFirst : LSBFirst;
122 this->UpdateRects = X11_NormalUpdate;
124 screen->pitch = SDL_Ximage->bytes_per_line;
128 SDL_SetError("Couldn't create XImage");
132 void X11_DestroyImage(_THIS, SDL_Surface *screen)
135 XDestroyImage(SDL_Ximage);
136 #ifndef NO_SHARED_MEMORY
138 XShmDetach(SDL_Display, &shminfo);
139 XSync(SDL_Display, False);
140 shmdt(shminfo.shmaddr);
142 #endif /* ! NO_SHARED_MEMORY */
146 screen->pixels = NULL;
150 /* Determine the number of CPUs in the system */
151 static int num_CPU(void)
153 static int num_cpus = 0;
156 #if defined(__LINUX__)
158 FILE *pstat = fopen("/proc/stat", "r");
160 while ( fgets(line, sizeof(line), pstat) ) {
161 if (SDL_memcmp(line, "cpu", 3) == 0 && line[3] != ' ') {
167 #elif defined(__IRIX__)
168 num_cpus = sysconf(_SC_NPROC_ONLN);
169 #elif defined(_SC_NPROCESSORS_ONLN)
170 /* number of processors online (SVR4.0MP compliant machines) */
171 num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
172 #elif defined(_SC_NPROCESSORS_CONF)
173 /* number of processors configured (SVR4.0MP compliant machines) */
174 num_cpus = sysconf(_SC_NPROCESSORS_CONF);
176 if ( num_cpus <= 0 ) {
183 int X11_ResizeImage(_THIS, SDL_Surface *screen, Uint32 flags)
187 X11_DestroyImage(this, screen);
188 if ( flags & SDL_OPENGL ) { /* No image when using GL */
191 retval = X11_SetupImage(this, screen);
192 /* We support asynchronous blitting on the display */
193 if ( flags & SDL_ASYNCBLIT ) {
194 /* This is actually slower on single-CPU systems,
195 probably because of CPU contention between the
196 X server and the application.
197 Note: Is this still true with XFree86 4.0?
199 if ( num_CPU() > 1 ) {
200 screen->flags |= SDL_ASYNCBLIT;
207 /* We don't actually allow hardware surfaces other than the main one */
208 int X11_AllocHWSurface(_THIS, SDL_Surface *surface)
212 void X11_FreeHWSurface(_THIS, SDL_Surface *surface)
217 int X11_LockHWSurface(_THIS, SDL_Surface *surface)
219 if ( (surface == SDL_VideoSurface) && blit_queued ) {
220 XSync(GFX_Display, False);
225 void X11_UnlockHWSurface(_THIS, SDL_Surface *surface)
230 int X11_FlipHWSurface(_THIS, SDL_Surface *surface)
235 static void X11_NormalUpdate(_THIS, int numrects, SDL_Rect *rects)
239 for (i = 0; i < numrects; ++i) {
240 if ( rects[i].w == 0 || rects[i].h == 0 ) { /* Clipped? */
243 XPutImage(GFX_Display, SDL_Window, SDL_GC, SDL_Ximage,
244 rects[i].x, rects[i].y,
245 rects[i].x, rects[i].y, rects[i].w, rects[i].h);
247 if ( SDL_VideoSurface->flags & SDL_ASYNCBLIT ) {
251 XSync(GFX_Display, False);
255 static void X11_MITSHMUpdate(_THIS, int numrects, SDL_Rect *rects)
257 #ifndef NO_SHARED_MEMORY
260 for ( i=0; i<numrects; ++i ) {
261 if ( rects[i].w == 0 || rects[i].h == 0 ) { /* Clipped? */
264 XShmPutImage(GFX_Display, SDL_Window, SDL_GC, SDL_Ximage,
265 rects[i].x, rects[i].y,
266 rects[i].x, rects[i].y, rects[i].w, rects[i].h,
269 if ( SDL_VideoSurface->flags & SDL_ASYNCBLIT ) {
273 XSync(GFX_Display, False);
275 #endif /* ! NO_SHARED_MEMORY */
278 /* There's a problem with the automatic refreshing of the display.
279 Even though the XVideo code uses the GFX_Display to update the
280 video memory, it appears that updating the window asynchronously
281 from a different thread will cause "blackouts" of the window.
282 This is a sort of a hacked workaround for the problem.
284 static int enable_autorefresh = 1;
286 void X11_DisableAutoRefresh(_THIS)
288 --enable_autorefresh;
291 void X11_EnableAutoRefresh(_THIS)
293 ++enable_autorefresh;
296 void X11_RefreshDisplay(_THIS)
298 /* Don't refresh a display that doesn't have an image (like GL)
299 Instead, post an expose event so the application can refresh.
301 if ( ! SDL_Ximage || (enable_autorefresh <= 0) ) {
305 #ifndef NO_SHARED_MEMORY
306 if ( this->UpdateRects == X11_MITSHMUpdate ) {
307 XShmPutImage(SDL_Display, SDL_Window, SDL_GC, SDL_Ximage,
308 0, 0, 0, 0, this->screen->w, this->screen->h,
311 #endif /* ! NO_SHARED_MEMORY */
313 XPutImage(SDL_Display, SDL_Window, SDL_GC, SDL_Ximage,
314 0, 0, 0, 0, this->screen->w, this->screen->h);
316 XSync(SDL_Display, False);