Mercurial > sdl-ios-xcode
annotate test/testpalette.c @ 1176:dd2a8deeb26d
Date: Mon, 17 Oct 2005 20:09:03 -0400
From: Mark Schreiber <mark7@alumni.cmu.edu>
To: ryan@clutteredmind.org
Subject: [PATCH]SDL mprotect() crash fix
(I'm going to throw this patch your way at the suggestion of #SDL --
for some reason, I had some difficulty sending it to the main list
last time, and I go bonkers subscribing to send each email or
patch...)
Currently, when I run SDL applications as non-root using
SDL_VIDEODRIVER=dga, the fbdev fallback mprotect()s read/write the
proper size of mmapped /dev/fb0 (7.5MB), but on framebuffer release
mprotect()s read-only the range by the entire size of my video memory
(128MB), which causes a segfault:
#0 0x002a9a27 in ?? () from /lib/libc.so.6
#1 0x04a63eb6 in SDL_XDGAUnmapFramebuffer (screen=3D0) at XF86DGA2.c:978
#2 0x04a63efc in SDL_XDGACloseFramebuffer (dpy=3D0x9d3f008, screen=3D0)
at XF86DGA2.c:268
#3 0x04a68b57 in DGA_Available () at SDL_dgavideo.c:98
#4 0x04a53677 in SDL_VideoInit (driver_name=3D0xbfb0bfc7 "dga", flags=3D0)
at SDL_video.c:180
#5 0x04a2613f in SDL_InitSubSystem (flags=3D32) at SDL.c:74
#6 0x04a2617c in SDL_Init (flags=3D32) at SDL.c:166
#7 0x08049722 in main (argc=3D1, argv=3D0x0) at testwin.c:32
This is SDL 1.2.8 on Fedora Core 4, radeon driver for a Radeon 9250,
xorg-x11-6.8.2-37.
I've attached a one-line patch against SDL CVS that updates the size
of the framebuffer at framebuffer map time so that the mprotect() on
unmap will be the same size. I'm not sure if this is the best
approach (i.e. one might want to retain the original value), but it
does make my SDL applications work without segfaulting.
-- Best of luck, Mark Schreiber
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Sat, 19 Nov 2005 18:57:00 +0000 |
parents | be9c9c8f6d53 |
children | aff0170f9f1b |
rev | line source |
---|---|
0 | 1 /* |
2 * testpalette.c | |
3 * | |
4 * A simple test of runtime palette modification for animation | |
5 * (using the SDL_SetPalette() API). | |
6 */ | |
7 | |
8 #include <stdio.h> | |
9 #include <stdlib.h> | |
10 #include <string.h> | |
11 #include <math.h> | |
12 | |
13 /* This isn't in the Windows headers */ | |
14 #ifndef M_PI | |
15 #define M_PI 3.14159265358979323846 | |
16 #endif | |
17 | |
18 #include <SDL.h> | |
19 | |
20 /* screen size */ | |
21 #define SCRW 640 | |
22 #define SCRH 480 | |
23 | |
24 #define NBOATS 5 | |
25 #define SPEED 2 | |
26 | |
27 #ifndef MIN | |
28 #define MIN(a, b) ((a) < (b) ? (a) : (b)) | |
29 #endif | |
30 #ifndef MAX | |
31 #define MAX(a, b) ((a) > (b) ? (a) : (b)) | |
32 #endif | |
33 | |
34 /* | |
35 * wave colours: Made by taking a narrow cross-section of a wave picture | |
36 * in Gimp, saving in PPM ascii format and formatting with Emacs macros. | |
37 */ | |
38 static SDL_Color wavemap[] = { | |
39 {0,2,103}, {0,7,110}, {0,13,117}, {0,19,125}, | |
40 {0,25,133}, {0,31,141}, {0,37,150}, {0,43,158}, | |
41 {0,49,166}, {0,55,174}, {0,61,182}, {0,67,190}, | |
42 {0,73,198}, {0,79,206}, {0,86,214}, {0,96,220}, | |
43 {5,105,224}, {12,112,226}, {19,120,227}, {26,128,229}, | |
44 {33,135,230}, {40,143,232}, {47,150,234}, {54,158,236}, | |
45 {61,165,238}, {68,173,239}, {75,180,241}, {82,188,242}, | |
46 {89,195,244}, {96,203,246}, {103,210,248}, {112,218,250}, | |
47 {124,224,250}, {135,226,251}, {146,229,251}, {156,231,252}, | |
48 {167,233,252}, {178,236,252}, {189,238,252}, {200,240,252}, | |
49 {211,242,252}, {222,244,252}, {233,247,252}, {242,249,252}, | |
50 {237,250,252}, {209,251,252}, {174,251,252}, {138,252,252}, | |
51 {102,251,252}, {63,250,252}, {24,243,252}, {7,225,252}, | |
52 {4,203,252}, {3,181,252}, {2,158,252}, {1,136,251}, | |
53 {0,111,248}, {0,82,234}, {0,63,213}, {0,50,192}, | |
54 {0,39,172}, {0,28,152}, {0,17,132}, {0,7,114} | |
55 }; | |
56 | |
1151
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
57 /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ |
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
58 static void quit(int rc) |
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
59 { |
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
60 SDL_Quit(); |
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
61 exit(rc); |
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
62 } |
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
63 |
0 | 64 static void sdlerr(char *when) |
65 { | |
66 fprintf(stderr, "SDL error: %s: %s\n", when, SDL_GetError()); | |
1151
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
67 quit(1); |
0 | 68 } |
69 | |
70 /* create a background surface */ | |
71 static SDL_Surface *make_bg(SDL_Surface *screen, int startcol) | |
72 { | |
73 int i; | |
74 SDL_Surface *bg = SDL_CreateRGBSurface(SDL_SWSURFACE, screen->w, screen->h, | |
75 8, 0, 0, 0, 0); | |
76 if(!bg) | |
77 sdlerr("creating background surface"); | |
78 | |
79 /* set the palette to the logical screen palette so that blits | |
80 won't be translated */ | |
81 SDL_SetColors(bg, screen->format->palette->colors, 0, 256); | |
82 | |
83 /* Make a wavy background pattern using colours 0-63 */ | |
84 if(SDL_LockSurface(bg) < 0) | |
85 sdlerr("locking background"); | |
86 for(i = 0; i < SCRH; i++) { | |
87 Uint8 *p = (Uint8 *)bg->pixels + i * bg->pitch; | |
88 int j, d; | |
89 d = 0; | |
90 for(j = 0; j < SCRW; j++) { | |
91 int v = MAX(d, -2); | |
92 v = MIN(v, 2); | |
93 if(i > 0) | |
94 v += p[-bg->pitch] + 65 - startcol; | |
95 p[j] = startcol + (v & 63); | |
96 d += ((rand() >> 3) % 3) - 1; | |
97 } | |
98 } | |
99 SDL_UnlockSurface(bg); | |
100 return(bg); | |
101 } | |
102 | |
103 /* | |
104 * Return a surface flipped horisontally. Only works for 8bpp; | |
105 * extension to arbitrary bitness is left as an exercise for the reader. | |
106 */ | |
107 static SDL_Surface *hflip(SDL_Surface *s) | |
108 { | |
109 int i; | |
110 SDL_Surface *z = SDL_CreateRGBSurface(SDL_SWSURFACE, s->w, s->h, 8, | |
111 0, 0, 0, 0); | |
112 /* copy palette */ | |
113 SDL_SetColors(z, s->format->palette->colors, | |
114 0, s->format->palette->ncolors); | |
115 if(SDL_LockSurface(s) < 0 || SDL_LockSurface(z) < 0) | |
116 sdlerr("locking flip images"); | |
117 | |
118 for(i = 0; i < s->h; i++) { | |
119 int j; | |
120 Uint8 *from = (Uint8 *)s->pixels + i * s->pitch; | |
121 Uint8 *to = (Uint8 *)z->pixels + i * z->pitch + s->w - 1; | |
122 for(j = 0; j < s->w; j++) | |
123 to[-j] = from[j]; | |
124 } | |
125 | |
126 SDL_UnlockSurface(z); | |
127 SDL_UnlockSurface(s); | |
128 return z; | |
129 } | |
130 | |
131 int main(int argc, char **argv) | |
132 { | |
133 SDL_Color cmap[256]; | |
134 SDL_Surface *screen; | |
135 SDL_Surface *bg; | |
136 SDL_Surface *boat[2]; | |
137 unsigned vidflags = 0; | |
138 unsigned start; | |
139 int fade_max = 400; | |
140 int fade_level, fade_dir; | |
141 int boatcols, frames, i, red; | |
142 int boatx[NBOATS], boaty[NBOATS], boatdir[NBOATS]; | |
143 int gamma_fade = 0; | |
144 int gamma_ramp = 0; | |
145 | |
146 if(SDL_Init(SDL_INIT_VIDEO) < 0) | |
147 sdlerr("initialising SDL"); | |
148 | |
149 while(--argc) { | |
150 ++argv; | |
151 if(strcmp(*argv, "-hw") == 0) | |
152 vidflags |= SDL_HWSURFACE; | |
153 else if(strcmp(*argv, "-fullscreen") == 0) | |
154 vidflags |= SDL_FULLSCREEN; | |
155 else if(strcmp(*argv, "-nofade") == 0) | |
156 fade_max = 1; | |
157 else if(strcmp(*argv, "-gamma") == 0) | |
158 gamma_fade = 1; | |
159 else if(strcmp(*argv, "-gammaramp") == 0) | |
160 gamma_ramp = 1; | |
161 else { | |
162 fprintf(stderr, | |
163 "usage: testpalette " | |
164 " [-hw] [-fullscreen] [-nofade] [-gamma] [-gammaramp]\n"); | |
1151
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
165 quit(1); |
0 | 166 } |
167 } | |
168 | |
169 /* Ask explicitly for 8bpp and a hardware palette */ | |
170 if(!(screen = SDL_SetVideoMode(SCRW, SCRH, 8, vidflags | SDL_HWPALETTE))) { | |
171 fprintf(stderr, "error setting %dx%d 8bpp indexed mode: %s\n", | |
172 SCRW, SCRH, SDL_GetError()); | |
1151
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
173 quit(1); |
0 | 174 } |
175 | |
176 if(!(boat[0] = SDL_LoadBMP("sail.bmp"))) | |
177 sdlerr("loading sail.bmp"); | |
178 /* We've chosen magenta (#ff00ff) as colour key for the boat */ | |
179 SDL_SetColorKey(boat[0], SDL_SRCCOLORKEY | SDL_RLEACCEL, | |
180 SDL_MapRGB(boat[0]->format, 0xff, 0x00, 0xff)); | |
181 boatcols = boat[0]->format->palette->ncolors; | |
182 boat[1] = hflip(boat[0]); | |
183 SDL_SetColorKey(boat[1], SDL_SRCCOLORKEY | SDL_RLEACCEL, | |
184 SDL_MapRGB(boat[1]->format, 0xff, 0x00, 0xff)); | |
185 | |
186 /* | |
187 * First set the physical screen palette to black, so the user won't | |
188 * see our initial drawing on the screen. | |
189 */ | |
190 memset(cmap, 0, sizeof(cmap)); | |
191 SDL_SetPalette(screen, SDL_PHYSPAL, cmap, 0, 256); | |
192 | |
193 /* | |
194 * Proper palette management is important when playing games with the | |
195 * colormap. We have divided the palette as follows: | |
196 * | |
197 * index 0..(boatcols-1): used for the boat | |
198 * index boatcols..(boatcols+63): used for the waves | |
199 */ | |
200 SDL_SetPalette(screen, SDL_LOGPAL, | |
201 boat[0]->format->palette->colors, 0, boatcols); | |
202 SDL_SetPalette(screen, SDL_LOGPAL, wavemap, boatcols, 64); | |
203 | |
204 /* | |
205 * Now the logical screen palette is set, and will remain unchanged. | |
206 * The boats already have the same palette so fast blits can be used. | |
207 */ | |
208 memcpy(cmap, screen->format->palette->colors, 256 * sizeof(SDL_Color)); | |
209 | |
210 /* save the index of the red colour for later */ | |
211 red = SDL_MapRGB(screen->format, 0xff, 0x00, 0x00); | |
212 | |
213 bg = make_bg(screen, boatcols); /* make a nice wavy background surface */ | |
214 | |
215 /* initial screen contents */ | |
216 if(SDL_BlitSurface(bg, NULL, screen, NULL) < 0) | |
217 sdlerr("blitting background to screen"); | |
218 SDL_Flip(screen); /* actually put the background on screen */ | |
219 | |
220 /* determine initial boat placements */ | |
221 for(i = 0; i < NBOATS; i++) { | |
222 boatx[i] = (rand() % (SCRW + boat[0]->w)) - boat[0]->w; | |
223 boaty[i] = i * (SCRH - boat[0]->h) / (NBOATS - 1); | |
224 boatdir[i] = ((rand() >> 5) & 1) * 2 - 1; | |
225 } | |
226 | |
227 start = SDL_GetTicks(); | |
228 frames = 0; | |
229 fade_dir = 1; | |
230 fade_level = 0; | |
231 do { | |
232 SDL_Event e; | |
233 SDL_Rect updates[NBOATS]; | |
234 SDL_Rect r; | |
235 int redphase; | |
236 | |
237 /* A small event loop: just exit on any key or mouse button event */ | |
238 while(SDL_PollEvent(&e)) { | |
239 if(e.type == SDL_KEYDOWN || e.type == SDL_QUIT | |
240 || e.type == SDL_MOUSEBUTTONDOWN) { | |
241 if(fade_dir < 0) | |
242 fade_level = 0; | |
243 fade_dir = -1; | |
244 } | |
245 } | |
246 | |
247 /* move boats */ | |
248 for(i = 0; i < NBOATS; i++) { | |
249 int old_x = boatx[i]; | |
250 /* update boat position */ | |
251 boatx[i] += boatdir[i] * SPEED; | |
252 if(boatx[i] <= -boat[0]->w || boatx[i] >= SCRW) | |
253 boatdir[i] = -boatdir[i]; | |
254 | |
255 /* paint over the old boat position */ | |
256 r.x = old_x; | |
257 r.y = boaty[i]; | |
258 r.w = boat[0]->w; | |
259 r.h = boat[0]->h; | |
260 if(SDL_BlitSurface(bg, &r, screen, &r) < 0) | |
261 sdlerr("blitting background"); | |
262 | |
263 /* construct update rectangle (bounding box of old and new pos) */ | |
264 updates[i].x = MIN(old_x, boatx[i]); | |
265 updates[i].y = boaty[i]; | |
266 updates[i].w = boat[0]->w + SPEED; | |
267 updates[i].h = boat[0]->h; | |
268 /* clip update rectangle to screen */ | |
269 if(updates[i].x < 0) { | |
270 updates[i].w += updates[i].x; | |
271 updates[i].x = 0; | |
272 } | |
273 if(updates[i].x + updates[i].w > SCRW) | |
274 updates[i].w = SCRW - updates[i].x; | |
275 } | |
276 | |
277 for(i = 0; i < NBOATS; i++) { | |
278 /* paint boat on new position */ | |
279 r.x = boatx[i]; | |
280 r.y = boaty[i]; | |
281 if(SDL_BlitSurface(boat[(boatdir[i] + 1) / 2], NULL, | |
282 screen, &r) < 0) | |
283 sdlerr("blitting boat"); | |
284 } | |
285 | |
286 /* cycle wave palette */ | |
287 for(i = 0; i < 64; i++) | |
288 cmap[boatcols + ((i + frames) & 63)] = wavemap[i]; | |
289 | |
290 if(fade_dir) { | |
291 /* Fade the entire palette in/out */ | |
292 fade_level += fade_dir; | |
293 | |
294 if(gamma_fade) { | |
295 /* Fade linearly in gamma level (lousy) */ | |
296 float level = (float)fade_level / fade_max; | |
297 if(SDL_SetGamma(level, level, level) < 0) | |
298 sdlerr("setting gamma"); | |
299 | |
300 } else if(gamma_ramp) { | |
301 /* Fade using gamma ramp (better) */ | |
302 Uint16 ramp[256]; | |
303 for(i = 0; i < 256; i++) | |
304 ramp[i] = (i * fade_level / fade_max) << 8; | |
305 if(SDL_SetGammaRamp(ramp, ramp, ramp) < 0) | |
306 sdlerr("setting gamma ramp"); | |
307 | |
308 } else { | |
309 /* Fade using direct palette manipulation (best) */ | |
310 memcpy(cmap, screen->format->palette->colors, | |
311 boatcols * sizeof(SDL_Color)); | |
312 for(i = 0; i < boatcols + 64; i++) { | |
313 cmap[i].r = cmap[i].r * fade_level / fade_max; | |
314 cmap[i].g = cmap[i].g * fade_level / fade_max; | |
315 cmap[i].b = cmap[i].b * fade_level / fade_max; | |
316 } | |
317 } | |
318 if(fade_level == fade_max) | |
319 fade_dir = 0; | |
320 } | |
321 | |
322 /* pulse the red colour (done after the fade, for a night effect) */ | |
323 redphase = frames % 64; | |
324 cmap[red].r = (int)(255 * sin(redphase * M_PI / 63)); | |
325 | |
326 SDL_SetPalette(screen, SDL_PHYSPAL, cmap, 0, boatcols + 64); | |
327 | |
328 /* update changed areas of the screen */ | |
329 SDL_UpdateRects(screen, NBOATS, updates); | |
330 frames++; | |
331 } while(fade_level > 0); | |
332 | |
333 printf("%d frames, %.2f fps\n", | |
334 frames, 1000.0 * frames / (SDL_GetTicks() - start)); | |
1151
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
335 |
be9c9c8f6d53
Removed atexit() from most of the test programs; atexit(SDL_Quit) isn't safe
Ryan C. Gordon <icculus@icculus.org>
parents:
0
diff
changeset
|
336 SDL_Quit(); |
0 | 337 return 0; |
338 } | |
339 |