Mercurial > sdl-ios-xcode
comparison src/video/x11/SDL_x11image.c @ 0:74212992fb08
Initial revision
author | Sam Lantinga <slouken@lokigames.com> |
---|---|
date | Thu, 26 Apr 2001 16:45:43 +0000 |
parents | |
children | eb6b76a95f2d |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:74212992fb08 |
---|---|
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$"; | |
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) | |
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) | |
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) | |
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) | |
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) | |
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) | |
247 { | |
248 return(-1); | |
249 } | |
250 void X11_FreeHWSurface(_THIS, SDL_Surface *surface) | |
251 { | |
252 return; | |
253 } | |
254 | |
255 int X11_LockHWSurface(_THIS, SDL_Surface *surface) | |
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) | |
264 { | |
265 return; | |
266 } | |
267 | |
268 int X11_FlipHWSurface(_THIS, SDL_Surface *surface) | |
269 { | |
270 return(0); | |
271 } | |
272 | |
273 /* Byte-swap the pixels in the display image */ | |
274 static void X11_SwapAllPixels(SDL_Surface *screen) | |
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) | |
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) | |
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) | |
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) | |
419 { | |
420 --enable_autorefresh; | |
421 } | |
422 | |
423 void X11_EnableAutoRefresh(_THIS) | |
424 { | |
425 ++enable_autorefresh; | |
426 } | |
427 | |
428 void X11_RefreshDisplay(_THIS) | |
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 } |