/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (hide annotations)
Wed Sep 5 17:11:21 2007 UTC (16 years, 7 months ago) by dpavlin
File size: 14093 byte(s)
import upstream CVS
1 dpavlin 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