This repository has been archived by the owner on Feb 11, 2021. It is now read-only.
/
SDL_x11image.c
340 lines (308 loc) · 9.49 KB
1
2
/*
SDL - Simple DirectMedia Layer
3
Copyright (C) 1997-2006 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
11
12
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
Lesser General Public License for more details.
14
15
16
17
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
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
30
31
32
33
34
#include "SDL_x11image_c.h"
#ifndef NO_SHARED_MEMORY
/* Shared memory error handler routine */
static int shm_error;
35
36
37
static int (*X_handler) (Display *, XErrorEvent *) = NULL;
static int
shm_errhandler (Display * d, XErrorEvent * e)
38
{
39
40
41
42
43
if (e->error_code == BadAccess) {
shm_error = True;
return (0);
} else
return (X_handler (d, e));
44
45
}
46
47
static void
try_mitshm (_THIS, SDL_Surface * screen)
48
{
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
/* Dynamic X11 may not have SHM entry points on this box. */
if ((use_mitshm) && (!SDL_X11_HAVE_SHM))
use_mitshm = 0;
if (!use_mitshm)
return;
shminfo.shmid = shmget (IPC_PRIVATE, screen->h * screen->pitch,
IPC_CREAT | 0777);
if (shminfo.shmid >= 0) {
shminfo.shmaddr = (char *) shmat (shminfo.shmid, 0, 0);
shminfo.readOnly = False;
if (shminfo.shmaddr != (char *) -1) {
shm_error = False;
X_handler = XSetErrorHandler (shm_errhandler);
XShmAttach (SDL_Display, &shminfo);
XSync (SDL_Display, True);
XSetErrorHandler (X_handler);
if (shm_error)
shmdt (shminfo.shmaddr);
} else {
shm_error = True;
}
shmctl (shminfo.shmid, IPC_RMID, NULL);
} else {
shm_error = True;
}
if (shm_error)
use_mitshm = 0;
if (use_mitshm)
screen->pixels = shminfo.shmaddr;
79
80
}
#endif /* ! NO_SHARED_MEMORY */
81
82
/* Various screen update functions available */
83
84
static void X11_NormalUpdate (_THIS, int numrects, SDL_Rect * rects);
static void X11_MITSHMUpdate (_THIS, int numrects, SDL_Rect * rects);
85
86
87
int
X11_SetupImage (_THIS, SDL_Surface * screen)
88
89
{
#ifndef NO_SHARED_MEMORY
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
try_mitshm (this, screen);
if (use_mitshm) {
SDL_Ximage = XShmCreateImage (SDL_Display, SDL_Visual,
this->hidden->depth, ZPixmap,
shminfo.shmaddr, &shminfo,
screen->w, screen->h);
if (!SDL_Ximage) {
XShmDetach (SDL_Display, &shminfo);
XSync (SDL_Display, False);
shmdt (shminfo.shmaddr);
screen->pixels = NULL;
goto error;
}
this->UpdateRects = X11_MITSHMUpdate;
}
if (!use_mitshm)
106
#endif /* not NO_SHARED_MEMORY */
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
{
int bpp;
screen->pixels = SDL_malloc (screen->h * screen->pitch);
if (screen->pixels == NULL) {
SDL_OutOfMemory ();
return -1;
}
bpp = screen->format->BytesPerPixel;
SDL_Ximage = XCreateImage (SDL_Display, SDL_Visual,
this->hidden->depth, ZPixmap, 0,
(char *) screen->pixels,
screen->w, screen->h, 32, 0);
if (SDL_Ximage == NULL)
goto error;
/* XPutImage will convert byte sex automatically */
SDL_Ximage->byte_order = (SDL_BYTEORDER == SDL_BIG_ENDIAN)
? MSBFirst : LSBFirst;
this->UpdateRects = X11_NormalUpdate;
}
screen->pitch = SDL_Ximage->bytes_per_line;
return (0);
error:
SDL_SetError ("Couldn't create XImage");
return 1;
132
133
}
134
135
void
X11_DestroyImage (_THIS, SDL_Surface * screen)
136
{
137
138
if (SDL_Ximage) {
XDestroyImage (SDL_Ximage);
139
#ifndef NO_SHARED_MEMORY
140
141
142
143
144
if (use_mitshm) {
XShmDetach (SDL_Display, &shminfo);
XSync (SDL_Display, False);
shmdt (shminfo.shmaddr);
}
145
#endif /* ! NO_SHARED_MEMORY */
146
147
148
149
150
SDL_Ximage = NULL;
}
if (screen) {
screen->pixels = NULL;
}
151
152
}
153
/* Determine the number of CPUs in the system */
154
155
static int
num_CPU (void)
156
{
157
static int num_cpus = 0;
158
159
if (!num_cpus) {
160
#if defined(__LINUX__)
161
162
163
164
165
166
167
168
169
170
char line[BUFSIZ];
FILE *pstat = fopen ("/proc/stat", "r");
if (pstat) {
while (fgets (line, sizeof (line), pstat)) {
if (SDL_memcmp (line, "cpu", 3) == 0 && line[3] != ' ') {
++num_cpus;
}
}
fclose (pstat);
}
171
#elif defined(__IRIX__)
172
num_cpus = sysconf (_SC_NPROC_ONLN);
173
#elif defined(_SC_NPROCESSORS_ONLN)
174
175
/* number of processors online (SVR4.0MP compliant machines) */
num_cpus = sysconf (_SC_NPROCESSORS_ONLN);
176
#elif defined(_SC_NPROCESSORS_CONF)
177
178
/* number of processors configured (SVR4.0MP compliant machines) */
num_cpus = sysconf (_SC_NPROCESSORS_CONF);
179
#endif
180
181
182
183
184
if (num_cpus <= 0) {
num_cpus = 1;
}
}
return num_cpus;
185
186
}
187
188
int
X11_ResizeImage (_THIS, SDL_Surface * screen, Uint32 flags)
189
{
190
int retval;
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
X11_DestroyImage (this, screen);
if (flags & SDL_INTERNALOPENGL) { /* No image when using GL */
retval = 0;
} else {
retval = X11_SetupImage (this, screen);
/* We support asynchronous blitting on the display */
if (flags & SDL_ASYNCBLIT) {
/* This is actually slower on single-CPU systems,
probably because of CPU contention between the
X server and the application.
Note: Is this still true with XFree86 4.0?
*/
if (num_CPU () > 1) {
screen->flags |= SDL_ASYNCBLIT;
}
}
}
return (retval);
210
211
212
}
/* We don't actually allow hardware surfaces other than the main one */
213
214
int
X11_AllocHWSurface (_THIS, SDL_Surface * surface)
215
{
216
return (-1);
217
}
218
219
220
void
X11_FreeHWSurface (_THIS, SDL_Surface * surface)
221
{
222
return;
223
224
}
225
226
int
X11_LockHWSurface (_THIS, SDL_Surface * surface)
227
{
228
229
230
231
232
if ((surface == SDL_VideoSurface) && blit_queued) {
XSync (GFX_Display, False);
blit_queued = 0;
}
return (0);
233
}
234
235
236
void
X11_UnlockHWSurface (_THIS, SDL_Surface * surface)
237
{
238
return;
239
240
}
241
242
int
X11_FlipHWSurface (_THIS, SDL_Surface * surface)
243
{
244
return (0);
245
246
}
247
248
static void
X11_NormalUpdate (_THIS, int numrects, SDL_Rect * rects)
249
{
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
int i;
for (i = 0; i < numrects; ++i) {
if (rects[i].w == 0 || rects[i].h == 0) { /* Clipped? */
continue;
}
XPutImage (GFX_Display, SDL_Window, SDL_GC, SDL_Ximage,
rects[i].x, rects[i].y,
rects[i].x, rects[i].y, rects[i].w, rects[i].h);
}
if (SDL_VideoSurface->flags & SDL_ASYNCBLIT) {
XFlush (GFX_Display);
blit_queued = 1;
} else {
XSync (GFX_Display, False);
}
266
267
}
268
269
static void
X11_MITSHMUpdate (_THIS, int numrects, SDL_Rect * rects)
270
271
{
#ifndef NO_SHARED_MEMORY
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
int i;
for (i = 0; i < numrects; ++i) {
if (rects[i].w == 0 || rects[i].h == 0) { /* Clipped? */
continue;
}
XShmPutImage (GFX_Display, SDL_Window, SDL_GC, SDL_Ximage,
rects[i].x, rects[i].y,
rects[i].x, rects[i].y, rects[i].w, rects[i].h, False);
}
if (SDL_VideoSurface->flags & SDL_ASYNCBLIT) {
XFlush (GFX_Display);
blit_queued = 1;
} else {
XSync (GFX_Display, False);
}
288
289
290
291
292
293
294
295
296
297
298
#endif /* ! NO_SHARED_MEMORY */
}
/* There's a problem with the automatic refreshing of the display.
Even though the XVideo code uses the GFX_Display to update the
video memory, it appears that updating the window asynchronously
from a different thread will cause "blackouts" of the window.
This is a sort of a hacked workaround for the problem.
*/
static int enable_autorefresh = 1;
299
300
void
X11_DisableAutoRefresh (_THIS)
301
{
302
--enable_autorefresh;
303
304
}
305
306
void
X11_EnableAutoRefresh (_THIS)
307
{
308
++enable_autorefresh;
309
310
}
311
312
void
X11_RefreshDisplay (_THIS)
313
{
314
315
316
317
318
319
320
/* Don't refresh a display that doesn't have an image (like GL)
Instead, post an expose event so the application can refresh.
*/
if (!SDL_Ximage || (enable_autorefresh <= 0)) {
SDL_PrivateExpose ();
return;
}
321
#ifndef NO_SHARED_MEMORY
322
323
324
325
326
327
328
if (this->UpdateRects == X11_MITSHMUpdate) {
XShmPutImage (SDL_Display, SDL_Window, SDL_GC, SDL_Ximage,
0, 0, SDL_CurrentWindow.offset_x,
SDL_CurrentWindow.offset_y,
SDL_CurrentDisplay.current_mode.w,
SDL_CurrentDisplay.current_mode.h, False);
} else
329
#endif /* ! NO_SHARED_MEMORY */
330
331
332
333
334
335
336
337
{
XPutImage (SDL_Display, SDL_Window, SDL_GC, SDL_Ximage,
0, 0, SDL_CurrentWindow.offset_x,
SDL_CurrentWindow.offset_y,
SDL_CurrentDisplay.current_mode.w,
SDL_CurrentDisplay.current_mode.h);
}
XSync (SDL_Display, False);
338
}
339
340
/* vi: set ts=4 sw=4 expandtab: */