• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2     SDL - Simple DirectMedia Layer
3     Copyright (C) 1997-2012 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 		screen->pixels = SDL_malloc(screen->h*screen->pitch);
106 		if ( screen->pixels == NULL ) {
107 			SDL_OutOfMemory();
108 			return -1;
109 		}
110 		SDL_Ximage = XCreateImage(SDL_Display, SDL_Visual,
111 					  this->hidden->depth, ZPixmap, 0,
112 					  (char *)screen->pixels,
113 					  screen->w, screen->h,
114 					  32, 0);
115 		if ( SDL_Ximage == NULL )
116 			goto error;
117 		/* XPutImage will convert byte sex automatically */
118 		SDL_Ximage->byte_order = (SDL_BYTEORDER == SDL_BIG_ENDIAN)
119 			                 ? MSBFirst : LSBFirst;
120 		this->UpdateRects = X11_NormalUpdate;
121 	}
122 	screen->pitch = SDL_Ximage->bytes_per_line;
123 	return(0);
124 
125 error:
126 	SDL_SetError("Couldn't create XImage");
127 	return 1;
128 }
129 
X11_DestroyImage(_THIS,SDL_Surface * screen)130 void X11_DestroyImage(_THIS, SDL_Surface *screen)
131 {
132 	if ( SDL_Ximage ) {
133 		XDestroyImage(SDL_Ximage);
134 #ifndef NO_SHARED_MEMORY
135 		if ( use_mitshm ) {
136 			XShmDetach(SDL_Display, &shminfo);
137 			XSync(SDL_Display, False);
138 			shmdt(shminfo.shmaddr);
139 		}
140 #endif /* ! NO_SHARED_MEMORY */
141 		SDL_Ximage = NULL;
142 	}
143 	if ( screen ) {
144 		screen->pixels = NULL;
145 	}
146 }
147 
148 /* Determine the number of CPUs in the system */
num_CPU(void)149 static int num_CPU(void)
150 {
151        static int num_cpus = 0;
152 
153        if(!num_cpus) {
154 #if defined(__LINUX__)
155            char line[BUFSIZ];
156            FILE *pstat = fopen("/proc/stat", "r");
157            if ( pstat ) {
158                while ( fgets(line, sizeof(line), pstat) ) {
159                    if (SDL_memcmp(line, "cpu", 3) == 0 && line[3] != ' ') {
160                        ++num_cpus;
161                    }
162                }
163                fclose(pstat);
164            }
165 #elif defined(__IRIX__)
166 	   num_cpus = sysconf(_SC_NPROC_ONLN);
167 #elif defined(_SC_NPROCESSORS_ONLN)
168 	   /* number of processors online (SVR4.0MP compliant machines) */
169            num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
170 #elif defined(_SC_NPROCESSORS_CONF)
171 	   /* number of processors configured (SVR4.0MP compliant machines) */
172            num_cpus = sysconf(_SC_NPROCESSORS_CONF);
173 #endif
174            if ( num_cpus <= 0 ) {
175                num_cpus = 1;
176            }
177        }
178        return num_cpus;
179 }
180 
X11_ResizeImage(_THIS,SDL_Surface * screen,Uint32 flags)181 int X11_ResizeImage(_THIS, SDL_Surface *screen, Uint32 flags)
182 {
183 	int retval;
184 
185 	X11_DestroyImage(this, screen);
186         if ( flags & SDL_OPENGL ) {  /* No image when using GL */
187         	retval = 0;
188         } else {
189 		retval = X11_SetupImage(this, screen);
190 		/* We support asynchronous blitting on the display */
191 		if ( flags & SDL_ASYNCBLIT ) {
192 			/* This is actually slower on single-CPU systems,
193 			   probably because of CPU contention between the
194 			   X server and the application.
195 			   Note: Is this still true with XFree86 4.0?
196 			*/
197 			if ( num_CPU() > 1 ) {
198 				screen->flags |= SDL_ASYNCBLIT;
199 			}
200 		}
201 	}
202 	return(retval);
203 }
204 
205 /* We don't actually allow hardware surfaces other than the main one */
X11_AllocHWSurface(_THIS,SDL_Surface * surface)206 int X11_AllocHWSurface(_THIS, SDL_Surface *surface)
207 {
208 	return(-1);
209 }
X11_FreeHWSurface(_THIS,SDL_Surface * surface)210 void X11_FreeHWSurface(_THIS, SDL_Surface *surface)
211 {
212 	return;
213 }
214 
X11_LockHWSurface(_THIS,SDL_Surface * surface)215 int X11_LockHWSurface(_THIS, SDL_Surface *surface)
216 {
217 	if ( (surface == SDL_VideoSurface) && blit_queued ) {
218 		XSync(GFX_Display, False);
219 		blit_queued = 0;
220 	}
221 	return(0);
222 }
X11_UnlockHWSurface(_THIS,SDL_Surface * surface)223 void X11_UnlockHWSurface(_THIS, SDL_Surface *surface)
224 {
225 	return;
226 }
227 
X11_FlipHWSurface(_THIS,SDL_Surface * surface)228 int X11_FlipHWSurface(_THIS, SDL_Surface *surface)
229 {
230 	return(0);
231 }
232 
X11_NormalUpdate(_THIS,int numrects,SDL_Rect * rects)233 static void X11_NormalUpdate(_THIS, int numrects, SDL_Rect *rects)
234 {
235 	int i;
236 
237 	for (i = 0; i < numrects; ++i) {
238 		if ( rects[i].w == 0 || rects[i].h == 0 ) { /* Clipped? */
239 			continue;
240 		}
241 		XPutImage(GFX_Display, SDL_Window, SDL_GC, SDL_Ximage,
242 			  rects[i].x, rects[i].y,
243 			  rects[i].x, rects[i].y, rects[i].w, rects[i].h);
244 	}
245 	if ( SDL_VideoSurface->flags & SDL_ASYNCBLIT ) {
246 		XFlush(GFX_Display);
247 		blit_queued = 1;
248 	} else {
249 		XSync(GFX_Display, False);
250 	}
251 }
252 
X11_MITSHMUpdate(_THIS,int numrects,SDL_Rect * rects)253 static void X11_MITSHMUpdate(_THIS, int numrects, SDL_Rect *rects)
254 {
255 #ifndef NO_SHARED_MEMORY
256 	int i;
257 
258 	for ( i=0; i<numrects; ++i ) {
259 		if ( rects[i].w == 0 || rects[i].h == 0 ) { /* Clipped? */
260 			continue;
261 		}
262 		XShmPutImage(GFX_Display, SDL_Window, SDL_GC, SDL_Ximage,
263 				rects[i].x, rects[i].y,
264 				rects[i].x, rects[i].y, rects[i].w, rects[i].h,
265 									False);
266 	}
267 	if ( SDL_VideoSurface->flags & SDL_ASYNCBLIT ) {
268 		XFlush(GFX_Display);
269 		blit_queued = 1;
270 	} else {
271 		XSync(GFX_Display, False);
272 	}
273 #endif /* ! NO_SHARED_MEMORY */
274 }
275 
276 /* There's a problem with the automatic refreshing of the display.
277    Even though the XVideo code uses the GFX_Display to update the
278    video memory, it appears that updating the window asynchronously
279    from a different thread will cause "blackouts" of the window.
280    This is a sort of a hacked workaround for the problem.
281 */
282 static int enable_autorefresh = 1;
283 
X11_DisableAutoRefresh(_THIS)284 void X11_DisableAutoRefresh(_THIS)
285 {
286 	--enable_autorefresh;
287 }
288 
X11_EnableAutoRefresh(_THIS)289 void X11_EnableAutoRefresh(_THIS)
290 {
291 	++enable_autorefresh;
292 }
293 
X11_RefreshDisplay(_THIS)294 void X11_RefreshDisplay(_THIS)
295 {
296 	/* Don't refresh a display that doesn't have an image (like GL)
297 	   Instead, post an expose event so the application can refresh.
298 	 */
299 	if ( ! SDL_Ximage || (enable_autorefresh <= 0) ) {
300 		SDL_PrivateExpose();
301 		return;
302 	}
303 #ifndef NO_SHARED_MEMORY
304 	if ( this->UpdateRects == X11_MITSHMUpdate ) {
305 		XShmPutImage(SDL_Display, SDL_Window, SDL_GC, SDL_Ximage,
306 				0, 0, 0, 0, this->screen->w, this->screen->h,
307 				False);
308 	} else
309 #endif /* ! NO_SHARED_MEMORY */
310 	{
311 		XPutImage(SDL_Display, SDL_Window, SDL_GC, SDL_Ximage,
312 			  0, 0, 0, 0, this->screen->w, this->screen->h);
313 	}
314 	XSync(SDL_Display, False);
315 }
316 
317