Mercurial > sdl-ios-xcode
annotate src/video/x11/SDL_x11image.c @ 161:eb6b76a95f2d
An expose event is now sent when using XVideo output.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Fri, 31 Aug 2001 21:08:30 +0000 |
parents | 74212992fb08 |
children | 39877400bd1e |
rev | line source |
---|---|
0 | 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" | |
161
eb6b76a95f2d
An expose event is now sent when using XVideo output.
Sam Lantinga <slouken@libsdl.org>
parents:
0
diff
changeset
|
32 #include "SDL_events_c.h" |
0 | 33 #include "SDL_x11image_c.h" |
34 | |
35 #if defined(__USLC__) | |
36 #ifdef HAVE_KSTAT | |
37 #undef HAVE_KSTAT | |
38 #endif | |
39 #include <unistd.h> | |
40 #endif | |
41 | |
42 #ifdef HAVE_KSTAT | |
43 #include <kstat.h> | |
44 #endif | |
45 | |
46 #ifndef NO_SHARED_MEMORY | |
47 | |
48 /* Shared memory information */ | |
49 extern int XShmQueryExtension(Display *dpy); /* Not in X11 headers */ | |
50 | |
51 /* Shared memory error handler routine */ | |
52 static int shm_error; | |
53 static int (*X_handler)(Display *, XErrorEvent *) = NULL; | |
54 static int shm_errhandler(Display *d, XErrorEvent *e) | |
55 { | |
56 if ( e->error_code == BadAccess ) { | |
57 ++shm_error; | |
58 return(0); | |
59 } else | |
60 return(X_handler(d,e)); | |
61 } | |
62 #endif /* ! NO_SHARED_MEMORY */ | |
63 | |
64 /* Various screen update functions available */ | |
65 static void X11_NormalUpdate(_THIS, int numrects, SDL_Rect *rects); | |
66 static void X11_MITSHMUpdate(_THIS, int numrects, SDL_Rect *rects); | |
67 | |
68 int X11_SetupImage(_THIS, SDL_Surface *screen) | |
69 { | |
70 #ifdef NO_SHARED_MEMORY | |
71 screen->pixels = malloc(screen->h*screen->pitch); | |
72 #else | |
73 /* Allocate shared memory if possible */ | |
74 if ( use_mitshm ) { | |
75 shminfo.shmid = shmget(IPC_PRIVATE, screen->h*screen->pitch, | |
76 IPC_CREAT|0777); | |
77 if ( shminfo.shmid >= 0 ) { | |
78 shminfo.shmaddr = (char *)shmat(shminfo.shmid, 0, 0); | |
79 shminfo.readOnly = False; | |
80 if ( shminfo.shmaddr != (char *)-1 ) { | |
81 shm_error = False; | |
82 X_handler = XSetErrorHandler(shm_errhandler); | |
83 XShmAttach(SDL_Display, &shminfo); | |
84 XSync(SDL_Display, True); | |
85 XSetErrorHandler(X_handler); | |
86 if ( shm_error == True ) | |
87 shmdt(shminfo.shmaddr); | |
88 } else { | |
89 shm_error = True; | |
90 } | |
91 shmctl(shminfo.shmid, IPC_RMID, NULL); | |
92 } else { | |
93 shm_error = True; | |
94 } | |
95 if ( shm_error == True ) | |
96 use_mitshm = 0; | |
97 } | |
98 if ( use_mitshm ) { | |
99 screen->pixels = shminfo.shmaddr; | |
100 } else { | |
101 screen->pixels = malloc(screen->h*screen->pitch); | |
102 } | |
103 #endif /* NO_SHARED_MEMORY */ | |
104 if ( screen->pixels == NULL ) { | |
105 SDL_OutOfMemory(); | |
106 return(-1); | |
107 } | |
108 | |
109 #ifdef NO_SHARED_MEMORY | |
110 { | |
111 int 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 (bpp == 3) ? 32 : bpp * 8, | |
117 0); | |
118 } | |
119 #else | |
120 if ( use_mitshm ) { | |
121 SDL_Ximage = XShmCreateImage(SDL_Display, SDL_Visual, | |
122 this->hidden->depth, ZPixmap, | |
123 shminfo.shmaddr, &shminfo, | |
124 screen->w, screen->h); | |
125 } else { | |
126 int bpp = screen->format->BytesPerPixel; | |
127 SDL_Ximage = XCreateImage(SDL_Display, SDL_Visual, | |
128 this->hidden->depth, ZPixmap, 0, | |
129 (char *)screen->pixels, | |
130 screen->w, screen->h, | |
131 (bpp == 3) ? 32 : bpp * 8, | |
132 0); | |
133 } | |
134 #endif /* NO_SHARED_MEMORY */ | |
135 if ( SDL_Ximage == NULL ) { | |
136 SDL_SetError("Couldn't create XImage"); | |
137 #ifndef NO_SHARED_MEMORY | |
138 if ( use_mitshm ) { | |
139 XShmDetach(SDL_Display, &shminfo); | |
140 XSync(SDL_Display, False); | |
141 shmdt(shminfo.shmaddr); | |
142 screen->pixels = NULL; | |
143 } | |
144 #endif /* ! NO_SHARED_MEMORY */ | |
145 return(-1); | |
146 } | |
147 screen->pitch = SDL_Ximage->bytes_per_line; | |
148 | |
149 /* Determine what blit function to use */ | |
150 #ifdef NO_SHARED_MEMORY | |
151 this->UpdateRects = X11_NormalUpdate; | |
152 #else | |
153 if ( use_mitshm ) { | |
154 this->UpdateRects = X11_MITSHMUpdate; | |
155 } else { | |
156 this->UpdateRects = X11_NormalUpdate; | |
157 } | |
158 #endif | |
159 return(0); | |
160 } | |
161 | |
162 void X11_DestroyImage(_THIS, SDL_Surface *screen) | |
163 { | |
164 if ( SDL_Ximage ) { | |
165 XDestroyImage(SDL_Ximage); | |
166 #ifndef NO_SHARED_MEMORY | |
167 if ( use_mitshm ) { | |
168 XShmDetach(SDL_Display, &shminfo); | |
169 XSync(SDL_Display, False); | |
170 shmdt(shminfo.shmaddr); | |
171 } | |
172 #endif /* ! NO_SHARED_MEMORY */ | |
173 SDL_Ximage = NULL; | |
174 } | |
175 if ( screen ) { | |
176 screen->pixels = NULL; | |
177 } | |
178 } | |
179 | |
180 /* This is a hack to see whether this system has more than 1 CPU */ | |
181 static int num_CPU(void) | |
182 { | |
183 static int num_cpus = 0; | |
184 | |
185 if(!num_cpus) { | |
186 #ifdef linux | |
187 char line[BUFSIZ]; | |
188 FILE *pstat = fopen("/proc/stat", "r"); | |
189 if ( pstat ) { | |
190 while ( fgets(line, sizeof(line), pstat) ) { | |
191 if (memcmp(line, "cpu", 3) == 0 && line[3] != ' ') { | |
192 ++num_cpus; | |
193 } | |
194 } | |
195 fclose(pstat); | |
196 } | |
197 #elif defined(HAVE_KSTAT) | |
198 kstat_ctl_t *kc = kstat_open(); | |
199 kstat_t *ks; | |
200 kstat_named_t *kn; | |
201 if(kc) { | |
202 if((ks = kstat_lookup(kc, "unix", -1, "system_misc")) | |
203 && kstat_read(kc, ks, NULL) != -1 | |
204 && (kn = kstat_data_lookup(ks, "ncpus"))) | |
205 #ifdef KSTAT_DATA_UINT32 | |
206 num_cpus = kn->value.ui32; | |
207 #else | |
208 num_cpus = kn->value.ul; /* needed in solaris <2.6 */ | |
209 #endif | |
210 kstat_close(kc); | |
211 } | |
212 #elif defined(__USLC__) | |
213 num_cpus = (int)sysconf(_SC_NPROCESSORS_CONF); | |
214 #endif | |
215 if ( num_cpus <= 0 ) { | |
216 num_cpus = 1; | |
217 } | |
218 } | |
219 return num_cpus; | |
220 } | |
221 | |
222 int X11_ResizeImage(_THIS, SDL_Surface *screen, Uint32 flags) | |
223 { | |
224 int retval; | |
225 | |
226 X11_DestroyImage(this, screen); | |
227 if ( flags & SDL_OPENGL ) { /* No image when using GL */ | |
228 retval = 0; | |
229 } else { | |
230 retval = X11_SetupImage(this, screen); | |
231 /* We support asynchronous blitting on the display */ | |
232 if ( flags & SDL_ASYNCBLIT ) { | |
233 /* This is actually slower on single-CPU systems, | |
234 probably because of CPU contention between the | |
235 X server and the application. | |
236 Note: Is this still true with XFree86 4.0? | |
237 */ | |
238 if ( num_CPU() > 1 ) { | |
239 screen->flags |= SDL_ASYNCBLIT; | |
240 } | |
241 } | |
242 } | |
243 return(retval); | |
244 } | |
245 | |
246 /* We don't actually allow hardware surfaces other than the main one */ | |
247 int X11_AllocHWSurface(_THIS, SDL_Surface *surface) | |
248 { | |
249 return(-1); | |
250 } | |
251 void X11_FreeHWSurface(_THIS, SDL_Surface *surface) | |
252 { | |
253 return; | |
254 } | |
255 | |
256 int X11_LockHWSurface(_THIS, SDL_Surface *surface) | |
257 { | |
258 if ( (surface == SDL_VideoSurface) && blit_queued ) { | |
259 XSync(GFX_Display, False); | |
260 blit_queued = 0; | |
261 } | |
262 return(0); | |
263 } | |
264 void X11_UnlockHWSurface(_THIS, SDL_Surface *surface) | |
265 { | |
266 return; | |
267 } | |
268 | |
269 int X11_FlipHWSurface(_THIS, SDL_Surface *surface) | |
270 { | |
271 return(0); | |
272 } | |
273 | |
274 /* Byte-swap the pixels in the display image */ | |
275 static void X11_SwapAllPixels(SDL_Surface *screen) | |
276 { | |
277 int x, y; | |
278 | |
279 switch (screen->format->BytesPerPixel) { | |
280 case 2: { | |
281 Uint16 *spot; | |
282 for ( y=0; y<screen->h; ++y ) { | |
283 spot = (Uint16 *) ((Uint8 *)screen->pixels + | |
284 y * screen->pitch); | |
285 for ( x=0; x<screen->w; ++x, ++spot ) { | |
286 *spot = SDL_Swap16(*spot); | |
287 } | |
288 } | |
289 } | |
290 break; | |
291 | |
292 case 4: { | |
293 Uint32 *spot; | |
294 for ( y=0; y<screen->h; ++y ) { | |
295 spot = (Uint32 *) ((Uint8 *)screen->pixels + | |
296 y * screen->pitch); | |
297 for ( x=0; x<screen->w; ++x, ++spot ) { | |
298 *spot = SDL_Swap32(*spot); | |
299 } | |
300 } | |
301 } | |
302 break; | |
303 | |
304 default: | |
305 /* should never get here */ | |
306 break; | |
307 } | |
308 } | |
309 static void X11_SwapPixels(SDL_Surface *screen, SDL_Rect *rect) | |
310 { | |
311 int x, minx, maxx; | |
312 int y, miny, maxy; | |
313 | |
314 switch (screen->format->BytesPerPixel) { | |
315 case 2: { | |
316 Uint16 *spot; | |
317 minx = rect->x; | |
318 maxx = rect->x + rect->w; | |
319 miny = rect->y; | |
320 maxy = rect->y + rect->h; | |
321 for ( y=miny; y<maxy; ++y ) { | |
322 spot = (Uint16 *) ((Uint8 *)screen->pixels + | |
323 y * screen->pitch + minx * 2); | |
324 for ( x=minx; x<maxx; ++x, ++spot ) { | |
325 *spot = SDL_Swap16(*spot); | |
326 } | |
327 } | |
328 } | |
329 break; | |
330 | |
331 case 4: { | |
332 Uint32 *spot; | |
333 minx = rect->x; | |
334 maxx = rect->x + rect->w; | |
335 miny = rect->y; | |
336 maxy = rect->y + rect->h; | |
337 for ( y=miny; y<maxy; ++y ) { | |
338 spot = (Uint32 *) ((Uint8 *)screen->pixels + | |
339 y * screen->pitch + minx * 4); | |
340 for ( x=minx; x<maxx; ++x, ++spot ) { | |
341 *spot = SDL_Swap32(*spot); | |
342 } | |
343 } | |
344 } | |
345 break; | |
346 | |
347 default: | |
348 /* should never get here */ | |
349 break; | |
350 } | |
351 } | |
352 | |
353 static void X11_NormalUpdate(_THIS, int numrects, SDL_Rect *rects) | |
354 { | |
355 int i; | |
356 | |
357 /* Check for endian-swapped X server, swap if necessary (VERY slow!) */ | |
358 if ( swap_pixels && | |
359 ((this->screen->format->BytesPerPixel%2) == 0) ) { | |
360 for ( i=0; i<numrects; ++i ) { | |
361 if ( ! rects[i].w ) { /* Clipped? */ | |
362 continue; | |
363 } | |
364 X11_SwapPixels(this->screen, rects + i); | |
365 XPutImage(GFX_Display, SDL_Window, SDL_GC, SDL_Ximage, | |
366 rects[i].x, rects[i].y, | |
367 rects[i].x, rects[i].y, rects[i].w, rects[i].h); | |
368 X11_SwapPixels(this->screen, rects + i); | |
369 } | |
370 } else { | |
371 for ( i=0; i<numrects; ++i ) { | |
372 if ( ! rects[i].w ) { /* Clipped? */ | |
373 continue; | |
374 } | |
375 XPutImage(GFX_Display, SDL_Window, SDL_GC, SDL_Ximage, | |
376 rects[i].x, rects[i].y, | |
377 rects[i].x, rects[i].y, rects[i].w, rects[i].h); | |
378 } | |
379 } | |
380 if ( SDL_VideoSurface->flags & SDL_ASYNCBLIT ) { | |
381 XFlush(GFX_Display); | |
382 ++blit_queued; | |
383 } else { | |
384 XSync(GFX_Display, False); | |
385 } | |
386 } | |
387 | |
388 static void X11_MITSHMUpdate(_THIS, int numrects, SDL_Rect *rects) | |
389 { | |
390 #ifndef NO_SHARED_MEMORY | |
391 int i; | |
392 | |
393 for ( i=0; i<numrects; ++i ) { | |
394 if ( ! rects[i].w ) { /* Clipped? */ | |
395 continue; | |
396 } | |
397 XShmPutImage(GFX_Display, SDL_Window, SDL_GC, SDL_Ximage, | |
398 rects[i].x, rects[i].y, | |
399 rects[i].x, rects[i].y, rects[i].w, rects[i].h, | |
400 False); | |
401 } | |
402 if ( SDL_VideoSurface->flags & SDL_ASYNCBLIT ) { | |
403 XFlush(GFX_Display); | |
404 ++blit_queued; | |
405 } else { | |
406 XSync(GFX_Display, False); | |
407 } | |
408 #endif /* ! NO_SHARED_MEMORY */ | |
409 } | |
410 | |
411 /* There's a problem with the automatic refreshing of the display. | |
412 Even though the XVideo code uses the GFX_Display to update the | |
413 video memory, it appears that updating the window asynchronously | |
414 from a different thread will cause "blackouts" of the window. | |
415 This is a sort of a hacked workaround for the problem. | |
416 */ | |
417 static int enable_autorefresh = 1; | |
418 | |
419 void X11_DisableAutoRefresh(_THIS) | |
420 { | |
421 --enable_autorefresh; | |
422 } | |
423 | |
424 void X11_EnableAutoRefresh(_THIS) | |
425 { | |
426 ++enable_autorefresh; | |
427 } | |
428 | |
429 void X11_RefreshDisplay(_THIS) | |
430 { | |
161
eb6b76a95f2d
An expose event is now sent when using XVideo output.
Sam Lantinga <slouken@libsdl.org>
parents:
0
diff
changeset
|
431 /* Don't refresh a display that doesn't have an image (like GL) |
eb6b76a95f2d
An expose event is now sent when using XVideo output.
Sam Lantinga <slouken@libsdl.org>
parents:
0
diff
changeset
|
432 Instead, post an expose event so the application can refresh. |
eb6b76a95f2d
An expose event is now sent when using XVideo output.
Sam Lantinga <slouken@libsdl.org>
parents:
0
diff
changeset
|
433 */ |
0 | 434 if ( ! SDL_Ximage || (enable_autorefresh <= 0) ) { |
161
eb6b76a95f2d
An expose event is now sent when using XVideo output.
Sam Lantinga <slouken@libsdl.org>
parents:
0
diff
changeset
|
435 SDL_PrivateExpose(); |
0 | 436 return; |
437 } | |
438 #ifndef NO_SHARED_MEMORY | |
439 if ( this->UpdateRects == X11_MITSHMUpdate ) { | |
440 XShmPutImage(SDL_Display, SDL_Window, SDL_GC, SDL_Ximage, | |
441 0, 0, 0, 0, this->screen->w, this->screen->h, | |
442 False); | |
443 } else { | |
444 #else | |
445 { | |
446 #endif /* ! NO_SHARED_MEMORY */ | |
447 /* Check for endian-swapped X server, swap if necessary */ | |
448 if ( swap_pixels && | |
449 ((this->screen->format->BytesPerPixel%2) == 0) ) { | |
450 X11_SwapAllPixels(this->screen); | |
451 XPutImage(SDL_Display, SDL_Window, SDL_GC, SDL_Ximage, | |
452 0, 0, 0, 0, this->screen->w, this->screen->h); | |
453 X11_SwapAllPixels(this->screen); | |
454 } else { | |
455 XPutImage(SDL_Display, SDL_Window, SDL_GC, SDL_Ximage, | |
456 0, 0, 0, 0, this->screen->w, this->screen->h); | |
457 } | |
458 } | |
459 XSync(SDL_Display, False); | |
460 } |