• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2     SDL - Simple DirectMedia Layer
3     Copyright (C) 1997-2006 Sam Lantinga
4 
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.
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     Lesser General Public License for more details.
14 
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
18 
19     Sam Lantinga
20     slouken@libsdl.org
21 */
22 #include "SDL_config.h"
23 
24 #include <stdio.h>
25 #include <unistd.h>
26 
27 #include "SDL_endian.h"
28 #include "../../events/SDL_events_c.h"
29 #include "SDL_x11image_c.h"
30 
31 #ifndef NO_SHARED_MEMORY
32 
33 /* Shared memory error handler routine */
34 static int shm_error;
35 static int (*X_handler)(Display *, XErrorEvent *) = NULL;
shm_errhandler(Display * d,XErrorEvent * e)36 static int shm_errhandler(Display *d, XErrorEvent *e)
37 {
38         if ( e->error_code == BadAccess ) {
39         	shm_error = True;
40         	return(0);
41         } else
42 		return(X_handler(d,e));
43 }
44 
try_mitshm(_THIS,SDL_Surface * screen)45 static void try_mitshm(_THIS, SDL_Surface *screen)
46 {
47 	/* Dynamic X11 may not have SHM entry points on this box. */
48 	if ((use_mitshm) && (!SDL_X11_HAVE_SHM))
49 		use_mitshm = 0;
50 
51 	if(!use_mitshm)
52 		return;
53 	shminfo.shmid = shmget(IPC_PRIVATE, screen->h*screen->pitch,
54 			       IPC_CREAT | 0777);
55 	if ( shminfo.shmid >= 0 ) {
56 		shminfo.shmaddr = (char *)shmat(shminfo.shmid, 0, 0);
57 		shminfo.readOnly = False;
58 		if ( shminfo.shmaddr != (char *)-1 ) {
59 			shm_error = False;
60 			X_handler = XSetErrorHandler(shm_errhandler);
61 			XShmAttach(SDL_Display, &shminfo);
62 			XSync(SDL_Display, True);
63 			XSetErrorHandler(X_handler);
64 			if ( shm_error )
65 				shmdt(shminfo.shmaddr);
66 		} else {
67 			shm_error = True;
68 		}
69 		shmctl(shminfo.shmid, IPC_RMID, NULL);
70 	} else {
71 		shm_error = True;
72 	}
73 	if ( shm_error )
74 		use_mitshm = 0;
75 	if ( use_mitshm )
76 		screen->pixels = shminfo.shmaddr;
77 }
78 #endif /* ! NO_SHARED_MEMORY */
79 
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);
83 
X11_SetupImage(_THIS,SDL_Surface * screen)84 int X11_SetupImage(_THIS, SDL_Surface *screen)
85 {
86 #ifndef NO_SHARED_MEMORY
87 	try_mitshm(this, screen);
88 	if(use_mitshm) {
89 		SDL_Ximage = XShmCreateImage(SDL_Display, SDL_Visual,
90 					     this->hidden->depth, ZPixmap,
91 					     shminfo.shmaddr, &shminfo,
92 					     screen->w, screen->h);
93 		if(!SDL_Ximage) {
94 			XShmDetach(SDL_Display, &shminfo);
95 			XSync(SDL_Display, False);
96 			shmdt(shminfo.shmaddr);
97 			screen->pixels = NULL;
98 			goto error;
99 		}
100 		this->UpdateRects = X11_MITSHMUpdate;
101 	}
102 	if(!use_mitshm)
103 #endif /* not NO_SHARED_MEMORY */
104 	{
105 		int bpp;
106 		screen->pixels = SDL_malloc(screen->h*screen->pitch);
107 		if ( screen->pixels == NULL ) {
108 			SDL_OutOfMemory();
109 			return -1;
110 		}
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,
116 					  32, 0);
117 		if ( SDL_Ximage == NULL )
118 			goto error;
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;
123 	}
124 	screen->pitch = SDL_Ximage->bytes_per_line;
125 	return(0);
126 
127 error:
128 	SDL_SetError("Couldn't create XImage");
129 	return 1;
130 }
131 
X11_DestroyImage(_THIS,SDL_Surface * screen)132 void X11_DestroyImage(_THIS, SDL_Surface *screen)
133 {
134 	if ( SDL_Ximage ) {
135 		XDestroyImage(SDL_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 		}
142 #endif /* ! NO_SHARED_MEMORY */
143 		SDL_Ximage = NULL;
144 	}
145 	if ( screen ) {
146 		screen->pixels = NULL;
147 	}
148 }
149 
150 /* Determine the number of CPUs in the system */
num_CPU(void)151 static int num_CPU(void)
152 {
153        static int num_cpus = 0;
154 
155        if(!num_cpus) {
156 #if defined(__LINUX__)
157            char line[BUFSIZ];
158            FILE *pstat = fopen("/proc/stat", "r");
159            if ( pstat ) {
160                while ( fgets(line, sizeof(line), pstat) ) {
161                    if (SDL_memcmp(line, "cpu", 3) == 0 && line[3] != ' ') {
162                        ++num_cpus;
163                    }
164                }
165                fclose(pstat);
166            }
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);
175 #endif
176            if ( num_cpus <= 0 ) {
177                num_cpus = 1;
178            }
179        }
180        return num_cpus;
181 }
182 
X11_ResizeImage(_THIS,SDL_Surface * screen,Uint32 flags)183 int X11_ResizeImage(_THIS, SDL_Surface *screen, Uint32 flags)
184 {
185 	int retval;
186 
187 	X11_DestroyImage(this, screen);
188         if ( flags & SDL_OPENGL ) {  /* No image when using GL */
189         	retval = 0;
190         } else {
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?
198 			*/
199 			if ( num_CPU() > 1 ) {
200 				screen->flags |= SDL_ASYNCBLIT;
201 			}
202 		}
203 	}
204 	return(retval);
205 }
206 
207 /* We don't actually allow hardware surfaces other than the main one */
X11_AllocHWSurface(_THIS,SDL_Surface * surface)208 int X11_AllocHWSurface(_THIS, SDL_Surface *surface)
209 {
210 	return(-1);
211 }
X11_FreeHWSurface(_THIS,SDL_Surface * surface)212 void X11_FreeHWSurface(_THIS, SDL_Surface *surface)
213 {
214 	return;
215 }
216 
X11_LockHWSurface(_THIS,SDL_Surface * surface)217 int X11_LockHWSurface(_THIS, SDL_Surface *surface)
218 {
219 	if ( (surface == SDL_VideoSurface) && blit_queued ) {
220 		XSync(GFX_Display, False);
221 		blit_queued = 0;
222 	}
223 	return(0);
224 }
X11_UnlockHWSurface(_THIS,SDL_Surface * surface)225 void X11_UnlockHWSurface(_THIS, SDL_Surface *surface)
226 {
227 	return;
228 }
229 
X11_FlipHWSurface(_THIS,SDL_Surface * surface)230 int X11_FlipHWSurface(_THIS, SDL_Surface *surface)
231 {
232 	return(0);
233 }
234 
X11_NormalUpdate(_THIS,int numrects,SDL_Rect * rects)235 static void X11_NormalUpdate(_THIS, int numrects, SDL_Rect *rects)
236 {
237 	int i;
238 
239 	for (i = 0; i < numrects; ++i) {
240 		if ( rects[i].w == 0 || rects[i].h == 0 ) { /* Clipped? */
241 			continue;
242 		}
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);
246 	}
247 	if ( SDL_VideoSurface->flags & SDL_ASYNCBLIT ) {
248 		XFlush(GFX_Display);
249 		blit_queued = 1;
250 	} else {
251 		XSync(GFX_Display, False);
252 	}
253 }
254 
X11_MITSHMUpdate(_THIS,int numrects,SDL_Rect * rects)255 static void X11_MITSHMUpdate(_THIS, int numrects, SDL_Rect *rects)
256 {
257 #ifndef NO_SHARED_MEMORY
258 	int i;
259 
260 	for ( i=0; i<numrects; ++i ) {
261 		if ( rects[i].w == 0 || rects[i].h == 0 ) { /* Clipped? */
262 			continue;
263 		}
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,
267 									False);
268 	}
269 	if ( SDL_VideoSurface->flags & SDL_ASYNCBLIT ) {
270 		XFlush(GFX_Display);
271 		blit_queued = 1;
272 	} else {
273 		XSync(GFX_Display, False);
274 	}
275 #endif /* ! NO_SHARED_MEMORY */
276 }
277 
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.
283 */
284 static int enable_autorefresh = 1;
285 
X11_DisableAutoRefresh(_THIS)286 void X11_DisableAutoRefresh(_THIS)
287 {
288 	--enable_autorefresh;
289 }
290 
X11_EnableAutoRefresh(_THIS)291 void X11_EnableAutoRefresh(_THIS)
292 {
293 	++enable_autorefresh;
294 }
295 
X11_RefreshDisplay(_THIS)296 void X11_RefreshDisplay(_THIS)
297 {
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.
300 	 */
301 	if ( ! SDL_Ximage || (enable_autorefresh <= 0) ) {
302 		SDL_PrivateExpose();
303 		return;
304 	}
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,
309 				False);
310 	} else
311 #endif /* ! NO_SHARED_MEMORY */
312 	{
313 		XPutImage(SDL_Display, SDL_Window, SDL_GC, SDL_Ximage,
314 			  0, 0, 0, 0, this->screen->w, this->screen->h);
315 	}
316 	XSync(SDL_Display, False);
317 }
318 
319