SDL-1.2.14
[sdl_omap.git] / src / video / x11 / SDL_x11image.c
1 /*
2     SDL - Simple DirectMedia Layer
3     Copyright (C) 1997-2009 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;
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
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
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
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 */
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
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 */
208 int X11_AllocHWSurface(_THIS, SDL_Surface *surface)
209 {
210         return(-1);
211 }
212 void X11_FreeHWSurface(_THIS, SDL_Surface *surface)
213 {
214         return;
215 }
216
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 }
225 void X11_UnlockHWSurface(_THIS, SDL_Surface *surface)
226 {
227         return;
228 }
229
230 int X11_FlipHWSurface(_THIS, SDL_Surface *surface)
231 {
232         return(0);
233 }
234
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
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
286 void X11_DisableAutoRefresh(_THIS)
287 {
288         --enable_autorefresh;
289 }
290
291 void X11_EnableAutoRefresh(_THIS)
292 {
293         ++enable_autorefresh;
294 }
295
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