/[pearpc]/src/system/ui/sdl/sysdisplay.cc
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /src/system/ui/sdl/sysdisplay.cc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (show annotations)
Wed Sep 5 17:11:21 2007 UTC (16 years, 6 months ago) by dpavlin
File size: 14093 byte(s)
import upstream CVS
1 /*
2 * PearPC
3 * sysdisplay.cc - screen access functions for SDL
4 *
5 * Copyright (C) 2004 Jens v.d. Heydt (mailme@vdh-webservice.de)
6 * Copyright (C) 2004 John Kelley (pearpc@kelley.ca)
7 * Copyright (C) 1999-2002 Stefan Weyergraf
8 * Copyright (C) 1999-2004 Sebastian Biallas (sb@biallas.net)
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include <cstdio>
25 #include <cstdlib>
26 #include <cstring>
27 #include <unistd.h>
28
29 #include <SDL.h>
30 #include <SDL_thread.h>
31
32 #ifdef __WIN32__
33 // We need ChangeDisplaySettings
34 #define WIN32_LEAN_AND_MEAN
35 #include <windows.h>
36 #undef FASTCALL
37 #endif
38
39
40 #include "system/display.h"
41 #include "system/sysexcept.h"
42 #include "system/systhread.h"
43 #include "system/sysvaccel.h"
44 #include "system/types.h"
45
46 #include "tools/data.h"
47 #include "tools/debug.h"
48 #include "tools/snprintf.h"
49
50 //#include "io/graphic/gcard.h"
51 #include "configparser.h"
52
53 //#define DPRINTF(a...)
54 #define DPRINTF(a...) ht_printf("[Display/SDL]: "a)
55
56 #include "syssdl.h"
57
58
59 uint SDLSystemDisplay::bitsPerPixelToXBitmapPad(uint bitsPerPixel)
60 {
61 if (bitsPerPixel <= 8) {
62 return 8;
63 } else if (bitsPerPixel <= 16) {
64 return 16;
65 } else {
66 return 32;
67 }
68 }
69
70 #define MASK(shift, size) (((1 << (size))-1)<<(shift))
71
72 void SDLSystemDisplay::dumpDisplayChar(const DisplayCharacteristics &chr)
73 {
74 fprintf(stderr, "\tdimensions: %d x %d pixels\n", chr.width, chr.height);
75 fprintf(stderr, "\tpixel size in bytes: %d\n", chr.bytesPerPixel);
76 fprintf(stderr, "\tpixel size in bits: %d\n", chr.bytesPerPixel*8);
77 fprintf(stderr, "\tred_mask: %08x (%d bits)\n", MASK(chr.redShift, chr.redSize), chr.redSize);
78 fprintf(stderr, "\tgreen_mask: %08x (%d bits)\n", MASK(chr.greenShift, chr.greenSize), chr.greenSize);
79 fprintf(stderr, "\tblue_mask: %08x (%d bits)\n", MASK(chr.blueShift, chr.blueSize), chr.blueSize);
80 fprintf(stderr, "\tdepth: %d\n", chr.redSize + chr.greenSize + chr.blueSize);
81 }
82
83 SDLSystemDisplay::SDLSystemDisplay(const char *title, const DisplayCharacteristics &chr, int redraw_ms)
84 : SystemDisplay(chr, redraw_ms)
85 {
86 mTitle = strdup(title);
87
88 gFrameBuffer = (byte*)malloc(mClientChar.width *
89 mClientChar.height * mClientChar.bytesPerPixel);
90 memset(gFrameBuffer, 0, mClientChar.width *
91 mClientChar.height * mClientChar.bytesPerPixel);
92 damageFrameBufferAll();
93
94 gSDLScreen = NULL;
95 mSDLFrameBuffer = NULL;
96 mChangingScreen = false;
97
98 sys_create_mutex(&mRedrawMutex);
99 }
100
101 void SDLSystemDisplay::finishMenu()
102 {
103 }
104
105 void SDLSystemDisplay::updateTitle()
106 {
107 String key;
108 int key_toggle_mouse_grab = gKeyboard->getKeyConfig().key_toggle_mouse_grab;
109 SystemKeyboard::convertKeycodeToString(key, key_toggle_mouse_grab);
110 String curTitle;
111 curTitle.assignFormat("%s - [%s %s mouse]", mTitle, key.contentChar(), (isMouseGrabbed() ? "disables" : "enables"));
112 SDL_WM_SetCaption(curTitle.contentChar(), NULL);
113 }
114
115 int SDLSystemDisplay::toString(char *buf, int buflen) const
116 {
117 return snprintf(buf, buflen, "SDL");
118 }
119
120 void SDLSystemDisplay::displayShow()
121 {
122 if (!isExposed()) return;
123
124 int firstDamagedLine, lastDamagedLine;
125 // We've got problems with races here because gcard_write1/2/4
126 // might set gDamageAreaFirstAddr, gDamageAreaLastAddr.
127 // We can't use mutexes in gcard for speed reasons. So we'll
128 // try to minimize the probability of loosing the race.
129 if (gDamageAreaFirstAddr > gDamageAreaLastAddr+3) {
130 return;
131 }
132 int damageAreaFirstAddr = gDamageAreaFirstAddr;
133 int damageAreaLastAddr = gDamageAreaLastAddr;
134 healFrameBuffer();
135 // end of race
136 damageAreaLastAddr += 3; // this is a hack. For speed reasons we
137 // inaccurately set gDamageAreaLastAddr
138 // to the first (not last) byte accessed
139 // accesses are up to 4 bytes "long".
140 firstDamagedLine = damageAreaFirstAddr / (mClientChar.width * mClientChar.bytesPerPixel);
141 lastDamagedLine = damageAreaLastAddr / (mClientChar.width * mClientChar.bytesPerPixel);
142 // Overflow may happen, because of the hack used above
143 // and others, that set lastAddr = 0xfffffff0 (damageFrameBufferAll())
144 if (lastDamagedLine >= mClientChar.height) {
145 lastDamagedLine = mClientChar.height-1;
146 }
147
148 sys_lock_mutex(mRedrawMutex);
149
150 if (SDL_MUSTLOCK(gSDLScreen)) SDL_LockSurface(gSDLScreen);
151
152 sys_convert_display(mClientChar, mSDLChar, gFrameBuffer,
153 (byte*)gSDLScreen->pixels, firstDamagedLine, lastDamagedLine);
154
155 if (SDL_MUSTLOCK(gSDLScreen)) SDL_UnlockSurface(gSDLScreen);
156
157 SDL_UpdateRect(gSDLScreen, 0, firstDamagedLine, mClientChar.width, lastDamagedLine-firstDamagedLine+1);
158
159 #if 0
160 if (mSDLFrameBuffer) { // using software-mode?
161 sys_convert_display(mClientChar, mSDLChar, gFrameBuffer,
162 mSDLFrameBuffer, firstDamagedLine, lastDamagedLine);
163 if (SDL_MUSTLOCK(gSDLScreen))
164 SDL_UnlockSurface(gSDLScreen);
165 } else {
166 // meaning we are in 32 bit. let sdl do a hardware-blit
167 // and convert Client to HostFramebuffer Pixelformat
168 SDL_Rect srcrect, dstrect;
169 srcrect.x = 0;
170 srcrect.y = firstDamagedLine;
171 srcrect.w = mClientChar.width;
172 srcrect.h = lastDamagedLine - firstDamagedLine+1;
173 dstrect.x = 0;
174 dstrect.y = firstDamagedLine;
175 if (SDL_MUSTLOCK(gSDLScreen))
176 SDL_UnlockSurface(gSDLScreen);
177 SDL_BlitSurface(mSDLClientScreen, &srcrect, gSDLScreen, &dstrect);
178 }
179
180 // If possible, we should use doublebuffering and SDL_Flip()
181 // SDL_Flip();
182 SDL_UpdateRect(gSDLScreen, 0, firstDamagedLine, mClientChar.width, lastDamagedLine-firstDamagedLine+1);
183 if (SDL_MUSTLOCK(gSDLScreen))
184 SDL_LockSurface(gSDLScreen);
185 #endif
186 sys_unlock_mutex(mRedrawMutex);
187 }
188
189 void SDLSystemDisplay::convertCharacteristicsToHost(DisplayCharacteristics &aHostChar, const DisplayCharacteristics &aClientChar)
190 {
191 aHostChar = aClientChar;
192 }
193
194 bool SDLSystemDisplay::changeResolution(const DisplayCharacteristics &aCharacteristics)
195 {
196 // We absolutely have to make sure that SDL_calls are only used
197 // in the thread, that did SDL_INIT and created Surfaces etc...
198 // This function behaves as a forward-function for changeResolution calls.
199 // It creates an SDL_Condition and pushes a userevent (no.1) onto
200 // the event queue. SDL_CondWait is used to wait for the event-thread
201 // to do the actual work (in reacting on the event and calling changeResolutionREAL)
202 // and finally signaling back to us, with SDL_Signal, that work is done.
203
204 // AND: we have to check if the call came from another thread.
205 // otherwise we would block and wait for our own thread to continue.-> endless loop
206
207 mSDLChartemp = aCharacteristics;
208 if (SDL_ThreadID() != mEventThreadID) { // called from a different thread than sdl eventloop
209 SDL_Event ev;
210 SDL_mutex *tmpmutex;
211
212 //DPRINTF("Forward handler got called\n");
213 ev.type = SDL_USEREVENT;
214 ev.user.code = 1;
215
216
217 tmpmutex = SDL_CreateMutex();
218 mWaitcondition = SDL_CreateCond();
219
220 SDL_LockMutex(tmpmutex);
221 SDL_PushEvent(&ev);
222
223 SDL_CondWait(mWaitcondition, tmpmutex);
224 //SDL_CondWait(mWaitcondition, tmpmutex, 5000);
225
226 SDL_UnlockMutex(tmpmutex);
227 SDL_DestroyMutex(tmpmutex);
228 SDL_DestroyCond(mWaitcondition);
229 return mChangeResRet;
230 } else {
231 // we can call it directly because we are in the same thread
232 //ht_printf("direct call\n");
233 return changeResolutionREAL(aCharacteristics);
234 }
235
236 }
237
238 bool SDLSystemDisplay::changeResolutionREAL(const DisplayCharacteristics &aCharacteristics)
239 {
240 Uint32 videoFlags = 0; /* Flags to pass to SDL_SetVideoMode */
241 DisplayCharacteristics chr;
242
243 DPRINTF("changeRes got called\n");
244
245 convertCharacteristicsToHost(chr, aCharacteristics);
246
247 /*
248 * From the SDL documentation:
249 * "Note: The bpp parameter is the number of bits per pixel,
250 * so a bpp of 24 uses the packed representation of 3 bytes/pixel.
251 * For the more common 4 bytes/pixel mode, use a bpp of 32.
252 * Somewhat oddly, both 15 and 16 will request a 2 bytes/pixel
253 * mode, but different pixel formats."
254 *
255 * Because of their odd convention, we have to mess with
256 * bytesPerPixel here.
257 */
258 uint bitsPerPixel;
259 switch (chr.bytesPerPixel) {
260 case 2:
261 bitsPerPixel = 15;
262 break;
263 case 4:
264 bitsPerPixel = 32;
265 break;
266 default:
267 ASSERT(0);
268 break;
269 }
270
271 DPRINTF("SDL: Changing resolution to %dx%dx%d\n", aCharacteristics.width, aCharacteristics.height,bitsPerPixel);
272
273 if (mFullscreen) videoFlags |= SDL_FULLSCREEN;
274 if (!SDL_VideoModeOK(chr.width, chr.height, bitsPerPixel, videoFlags)) {
275 /*
276 * We can't this mode in fullscreen
277 * so we try if we can use it in windowed mode.
278 */
279 if (!mFullscreen) return false;
280 videoFlags &= ~SDL_FULLSCREEN;
281 if (!SDL_VideoModeOK(chr.width, chr.height, bitsPerPixel, videoFlags)) {
282 return false;
283 }
284 mFullscreen = false;
285 /*
286 * We can use the mode in windowed mode.
287 */
288 }
289
290 if (SDL_VideoModeOK(chr.width, chr.height, bitsPerPixel, videoFlags | SDL_SWSURFACE)) {
291 videoFlags |= SDL_SWSURFACE;
292 DPRINTF("can use SWSURFACE\n");
293 if (SDL_VideoModeOK(chr.width, chr.height, bitsPerPixel, videoFlags | SDL_HWACCEL)) {
294 videoFlags |= SDL_HWACCEL;
295 DPRINTF("can use HWACCEL\n");
296 }
297 }
298
299 mSDLChar = chr;
300 mClientChar = aCharacteristics;
301
302 sys_lock_mutex(mRedrawMutex);
303 #if 0
304 if (gSDLScreen && SDL_MUSTLOCK(gSDLScreen)) {
305 SDL_UnlockSurface(gSDLScreen);
306 }
307 #endif
308
309 gSDLScreen = SDL_SetVideoMode(aCharacteristics.width, aCharacteristics.height,
310 bitsPerPixel, videoFlags);
311
312 if (!gSDLScreen) {
313 // FIXME: this is really bad.
314 ht_printf("SDL: FATAL: can't switch mode?!\n");
315 exit(1);
316 }
317
318 #ifdef __WIN32__
319 if (videoFlags & SDL_FULLSCREEN) {
320 DEVMODE refresh;
321 refresh.dmDisplayFrequency = chr.vsyncFrequency;
322 ChangeDisplaySettings(&refresh, DM_DISPLAYFREQUENCY);
323 }
324 #else
325 // FIXME: implement refreshrate change for other host OS
326 #endif
327
328 mFullscreenChanged = videoFlags & SDL_FULLSCREEN;
329 if (gSDLScreen->pitch != aCharacteristics.width * aCharacteristics.bytesPerPixel) {
330 // FIXME: this is really bad.
331 ht_printf("SDL: FATAL: new mode has scanline gap. Trying to revert to old mode.\n");
332 exit(1);
333 }
334
335 gFrameBuffer = (byte*)realloc(gFrameBuffer, mClientChar.width *
336 mClientChar.height * mClientChar.bytesPerPixel);
337 #if 0
338 if (mSDLClientScreen) {
339 // if this is a modechange, free the old surface first.
340 if (SDL_MUSTLOCK(gSDLScreen))
341 SDL_UnlockSurface(gSDLScreen);
342 SDL_FreeSurface(mSDLClientScreen);
343 }
344
345 // Init Clientsurface
346 mSDLClientScreen = SDL_CreateRGBSurface(SDL_HWSURFACE, mClientChar.width, mClientChar.height,
347 bitsPerPixel, 0x0000ff00, 0x00ff0000, 0xff000000, 0);
348 // Mask isn't important since we only use it as a buffer and never let SDL draw with it...
349 // Though it is used in 32 bit, and then the mask is ok
350
351 if (!mSDLClientScreen) {
352 ht_printf("SDL: FATAL: can't create surface\n");
353 exit(1);
354 }
355
356 gFrameBuffer = (byte*)mSDLClientScreen->pixels;
357
358 // are we running in 32 bit? use sdl, else use pearpc's software convert
359 if (bitsPerPixel != 32) {
360 mSDLFrameBuffer = (byte*)gSDLScreen->pixels;
361 } else {
362 mSDLFrameBuffer = NULL;
363 }
364
365 // clean up
366 if (SDL_MUSTLOCK(gSDLScreen))
367 SDL_LockSurface(gSDLScreen);
368 if (SDL_MUSTLOCK(mSDLClientScreen))
369 SDL_LockSurface(mSDLClientScreen);
370 #endif
371
372 //ht_printf("SDL rmask %08x, gmask %08x, bmask %08x\n", gSDLScreen->format->Rmask,
373 // gSDLScreen->format->Gmask, gSDLScreen->format->Bmask);
374 //
375 mSDLChar.redSize = 8 - gSDLScreen->format->Rloss;
376 mSDLChar.greenSize = 8 - gSDLScreen->format->Gloss;
377 mSDLChar.blueSize = 8 - gSDLScreen->format->Bloss;
378 mSDLChar.redShift = gSDLScreen->format->Rshift;
379 mSDLChar.greenShift = gSDLScreen->format->Gshift;
380 mSDLChar.blueShift = gSDLScreen->format->Bshift;
381
382 damageFrameBufferAll();
383 sys_unlock_mutex(mRedrawMutex);
384 return true;
385 }
386
387 void SDLSystemDisplay::getHostCharacteristics(Container &modes)
388 {
389 #ifdef __WIN32__
390 DEVMODE dm;
391 DWORD num = 0;
392 while (EnumDisplaySettings(NULL, num++, &dm)) {
393 switch (dm.dmBitsPerPel) {
394 case 15:
395 case 16:
396 dm.dmBitsPerPel = 2;
397 break;
398 case 32:
399 dm.dmBitsPerPel = 4;
400 break;
401 default:
402 continue;
403 }
404 DisplayCharacteristics *dc = new DisplayCharacteristics;
405 dc->width = dm.dmPelsWidth;
406 dc->height = dm.dmPelsHeight;
407 dc->bytesPerPixel = dm.dmBitsPerPel;
408 dc->scanLineLength = -1;
409 dc->vsyncFrequency = dm.dmDisplayFrequency;
410 dc->redShift = -1;
411 dc->redSize = -1;
412 dc->greenShift = -1;
413 dc->greenSize = -1;
414 dc->blueShift = -1;
415 dc->blueSize = -1;
416 modes.insert(dc);
417 }
418 #else
419 #if 0
420 //ARGL, won't work
421
422 SDL_Rect **modes;
423 modes = SDL_ListModes(NULL, SDL_FULLSCREEN);
424
425 /* Check is there are any modes available */
426 if (modes == (SDL_Rect **)0){
427 DPRINTF("No modes available!\n");
428 return;
429 }
430
431 /* Check if our resolution is restricted */
432 if (modes == (SDL_Rect **)-1) {
433 return;
434 } else {
435 }
436 #endif
437 #endif
438 }
439
440 void SDLSystemDisplay::setMouseGrab(bool enable)
441 {
442 if (enable == isMouseGrabbed()) return;
443 SystemDisplay::setMouseGrab(enable);
444 if (enable) {
445 // SDL_ShowCursor(SDL_DISABLE);
446 SDL_SetCursor(mInvisibleCursor);
447 SDL_WM_GrabInput(SDL_GRAB_ON);
448 } else {
449 SDL_SetCursor(mVisibleCursor);
450 SDL_WM_GrabInput(SDL_GRAB_OFF);
451 // SDL_ShowCursor(SDL_ENABLE);
452 }
453 }
454
455 void SDLSystemDisplay::initCursor()
456 {
457 mVisibleCursor = SDL_GetCursor();
458 // FIXME: need a portable way of getting cursor sizes
459 byte mask[64];
460 memset(mask, 0, sizeof mask);
461 mInvisibleCursor = SDL_CreateCursor(mask, mask, 16, 16, 0, 0);
462 }
463
464 SystemDisplay *allocSystemDisplay(const char *title, const DisplayCharacteristics &chr, int redraw_ms)
465 {
466 DPRINTF("Making new window %d x %d\n", chr.width, chr.height);
467 return new SDLSystemDisplay(title, chr, redraw_ms);
468 }

  ViewVC Help
Powered by ViewVC 1.1.26