SDL-1.2.14
[sdl_omap.git] / src / video / x11 / SDL_x11image.c
CommitLineData
e14743d1 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 */
34static int shm_error;
35static int (*X_handler)(Display *, XErrorEvent *) = NULL;
36static 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
45static 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 */
81static void X11_NormalUpdate(_THIS, int numrects, SDL_Rect *rects);
82static void X11_MITSHMUpdate(_THIS, int numrects, SDL_Rect *rects);
83
84int 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
127error:
128 SDL_SetError("Couldn't create XImage");
129 return 1;
130}
131
132void 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 */
151static 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
183int 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 */
208int X11_AllocHWSurface(_THIS, SDL_Surface *surface)
209{
210 return(-1);
211}
212void X11_FreeHWSurface(_THIS, SDL_Surface *surface)
213{
214 return;
215}
216
217int 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}
225void X11_UnlockHWSurface(_THIS, SDL_Surface *surface)
226{
227 return;
228}
229
230int X11_FlipHWSurface(_THIS, SDL_Surface *surface)
231{
232 return(0);
233}
234
235static 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
255static 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*/
284static int enable_autorefresh = 1;
285
286void X11_DisableAutoRefresh(_THIS)
287{
288 --enable_autorefresh;
289}
290
291void X11_EnableAutoRefresh(_THIS)
292{
293 ++enable_autorefresh;
294}
295
296void 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