Annotation of previous/src/fast_screen.c, revision 1.1.1.1

1.1       root        1: /*
                      2:   Hatari - screen.c
                      3: 
                      4:   This file is distributed under the GNU Public License, version 2 or at your
                      5:   option any later version. Read the file gpl.txt for details.
                      6: 
                      7:  (SC) Simon Schubiger - most of it rewritten for Previous NeXT emualtor
                      8: */
                      9: 
                     10: #include <SDL.h>
                     11: #include <SDL_endian.h>
                     12: #include <SDL_blendmode.h>
                     13: 
                     14: #if 0
                     15: void blitDimension(SDL_Texture* tex) {}
                     16: #include "screen.c"
                     17: #else
                     18: 
                     19: const char Screen_fileid[] = "Previous fast_screen.c : " __DATE__ " " __TIME__;
                     20: 
                     21: #include "main.h"
                     22: #include "configuration.h"
                     23: #include "log.h"
                     24: #include "m68000.h"
                     25: #include "dimension.h"
                     26: #include "paths.h"
                     27: #include "screen.h"
                     28: #include "control.h"
                     29: #include "convert/routines.h"
                     30: #include "resolution.h"
                     31: #include "statusbar.h"
                     32: #include "video.h"
                     33: 
                     34: SDL_Window*  sdlWindow;
                     35: SDL_Surface* sdlscrn = NULL;   /* The SDL screen surface */
                     36: int nScreenZoomX, nScreenZoomY;/* Zooming factors, used for scaling mouse motions */
                     37: 
                     38: /* extern for shortcuts and falcon/hostscreen.c */
                     39: volatile bool bGrabMouse    = false;      /* Grab the mouse cursor in the window */
                     40: volatile bool bInFullScreen = false;   /* true if in full screen */
                     41: 
                     42: static SDL_Thread*   repaintThread;
                     43: static SDL_sem*      initLatch;
                     44: static SDL_atomic_t  blitUI;           /* When value = 1, the repaint thread will blit the sldscrn surface to the screen on the next redraw */
                     45: static SDL_atomic_t  blitStatusBar;    /* When value = 1, the repaint thread will blit the sldscrn status bar on the next redraw */
                     46: static bool          doUIblit;
                     47: static SDL_Rect      saveWindowBounds; /* Window bounds before going fullscreen. Used to restore window size & position. */
                     48: static void*         uiBuffer;         /* uiBuffer used for ui texture */
                     49: static SDL_SpinLock  uiBufferLock;     /* Lock for concurrent access to UI buffer between main thread and repainter */
                     50: static Uint32        mask;             /* green screen mask for transparent UI areas */
                     51: static volatile bool doRepaint  = true; /* Repaint thread runs while true */
                     52: 
                     53: static Uint32 BW2RGB[0x400];
                     54: static Uint32 COL2RGB[0x10000];
                     55: 
                     56: static Uint32 bw2rgb(SDL_PixelFormat* format, int bw) {
                     57:     switch(bw & 3) {
                     58:         case 3:  return SDL_MapRGB(format, 0,   0,   0);
                     59:         case 2:  return SDL_MapRGB(format, 85,  85,  85);
                     60:         case 1:  return SDL_MapRGB(format, 170, 170, 170);
                     61:         case 0:  return SDL_MapRGB(format, 255, 255, 255);
                     62:         default: return 0;
                     63:     }
                     64: }
                     65: 
                     66: static Uint32 col2rgb(SDL_PixelFormat* format, int col) {
                     67:     int r = col & 0xF000; r >>= 12; r |= r << 4;
                     68:     int g = col & 0x0F00; g >>= 8;  g |= g << 4;
                     69:     int b = col & 0x00F0; b >>= 4;  b |= b << 4;
                     70:     return SDL_MapRGB(format, r,   g,   b);
                     71: }
                     72: 
                     73: /*
                     74:  BW format is 2bit per pixel
                     75:  */
                     76: static void blitBW(SDL_Texture* tex) {
                     77:     void* pixels;
                     78:     int   d;
                     79:     int   pitch = ConfigureParams.System.bTurbo ? 280 : 288;
                     80:     SDL_LockTexture(tex, NULL, &pixels, &d);
                     81:     Uint32* dst = (Uint32*)pixels;
                     82:     for(int y = 0; y < 832; y++) {
                     83:         int src     = y * pitch;
                     84:         for(int x = 0; x < 280; x++, src++) {
                     85:             int idx = NEXTVideo[src] * 4;
                     86:             *dst++  = BW2RGB[idx+0];
                     87:             *dst++  = BW2RGB[idx+1];
                     88:             *dst++  = BW2RGB[idx+2];
                     89:             *dst++  = BW2RGB[idx+3];
                     90:         }
                     91:     }
                     92:     SDL_UnlockTexture(tex);
                     93: }
                     94: 
                     95: /*
                     96:  Color format is 4bit per pixel, big-endian: RGBx
                     97:  */
                     98: static void blitColor(SDL_Texture* tex) {
                     99:     void* pixels;
                    100:     int   d;
                    101:     int pitch = ConfigureParams.System.bTurbo ? 1120 : 1152;
                    102:     SDL_LockTexture(tex, NULL, &pixels, &d);
                    103:     Uint32* dst = (Uint32*)pixels;
                    104:     for(int y = 0; y < 832; y++) {
                    105:         Uint16* src = (Uint16*)NEXTColorVideo + (y*pitch);
                    106:         for(int x = 0; x < 1120; x++) {
                    107:             *dst++ = COL2RGB[*src++];
                    108:         }
                    109:     }
                    110:     SDL_UnlockTexture(tex);
                    111: }
                    112: 
                    113: extern 
                    114: 
                    115: /*
                    116:  Dimension format is 8bit per pixel, big-endian: RRGGGBBBA
                    117:  */
                    118: void blitDimension(SDL_Texture* tex) {
                    119: #if ENABLE_DIMENSION
                    120:     Uint32* src = (Uint32*)&ND_vram[ND_vram_off];
                    121:     void*   pixels;
                    122:     int     d;
                    123:     Uint32  format;
                    124:     SDL_QueryTexture(tex, &format, &d, &d, &d);
                    125:     SDL_LockTexture(tex, NULL, &pixels, &d);
                    126:     Uint32* dst = (Uint32*)pixels;
                    127:     if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
                    128:         /* Add big-endian accelerated blit loops as needed */
                    129:         switch (format) {
                    130:             default: {
                    131:                 /* fallback to SDL_MapRGB */
                    132:                 SDL_PixelFormat* pformat = SDL_AllocFormat(format);
                    133:                 for(int y = 832; --y >= 0;) {
                    134:                     for(int x = 1120; --x >= 0;) {
                    135:                         Uint32 v = *src++;
                    136:                         *dst++   = SDL_MapRGB(pformat, (v >> 24) & 0xFF, (v>>16) & 0xFF, (v>>8) & 0xFF);
                    137:                     }
                    138:                     src += 1152 - 1120;
                    139:                 }
                    140:                 SDL_FreeFormat(pformat);
                    141:                 break;
                    142:             }
                    143:         }
                    144:     } else {
                    145:         /* Add little-endian accelerated blit loops as needed */
                    146:         switch (format) {
                    147:             case SDL_PIXELFORMAT_ARGB8888:
                    148:                 for(int y = 832; --y >= 0;) {
                    149:                     for(int x = 1120; --x >= 0;) {
                    150:                         // Uint32 LE: AABBGGRR
                    151:                         // Target:    AARRGGBB
                    152:                         Uint32 v = *src++;
                    153:                         *dst++   = (v & 0xFF000000) | ((v<<16) &0x00FF0000) | (v &0x0000FF00) | ((v>>16) &0x000000FF);
                    154:                     }
                    155:                     src += 1152 - 1120;
                    156:                 }
                    157:                 break;
                    158:             default: {
                    159:                 /* fallback to SDL_MapRGB */
                    160:                 SDL_PixelFormat* pformat = SDL_AllocFormat(format);
                    161:                 for(int y = 832; --y >= 0;) {
                    162:                     for(int x = 1120; --x >= 0;) {
                    163:                         Uint32 v = SDL_Swap32(*src++);
                    164:                         *dst++   = SDL_MapRGB(pformat, (v >> 24) & 0xFF, (v>>16) & 0xFF, (v>>8) & 0xFF);
                    165:                     }
                    166:                     src += 1152 - 1120;
                    167:                 }
                    168:                 SDL_FreeFormat(pformat);
                    169:                 break;
                    170:             }
                    171:         }
                    172:     }
                    173:     SDL_UnlockTexture(tex);
                    174: #endif
                    175: }
                    176: 
                    177: /*
                    178:  Blit NeXT framebuffer to texture.
                    179:  */
                    180: static void blitScreen(SDL_Texture* tex) {
                    181: #if ENABLE_DIMENSION
                    182:     if (ConfigureParams.Screen.nMonitorType==MONITOR_TYPE_DIMENSION) {
                    183:         blitDimension(tex);
                    184:         return;
                    185:     }
                    186: #endif
                    187:     if(ConfigureParams.System.bColor) {
                    188:         blitColor(tex);
                    189:     } else {
                    190:         blitBW(tex);
                    191:     }
                    192: }
                    193: 
                    194: /*
                    195:  Initializes sdl graphics and the enter repaint loop.
                    196:  Loop: blits the NeXT framebuffer to the fbTexture, blends with the GUI surface and
                    197:  shows it.
                    198:  */
                    199: static int repainter(void* unused) {
                    200:     int width;
                    201:     int height;
                    202: 
                    203:     SDL_GetWindowSize(sdlWindow, &width, &height);
                    204:     
                    205:     SDL_Renderer* sdlRenderer;
                    206:     SDL_Texture*  uiTexture;
                    207:     SDL_Texture*  fbTexture;
                    208:     SDL_Rect      statusBar = {0,832,width,height-832};
                    209:     
                    210:     Uint32 r, g, b, a;
                    211:     
                    212:     sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
                    213:     SDL_RenderSetLogicalSize(sdlRenderer, width, height);
                    214: 
                    215:     uiTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_UNKNOWN, SDL_TEXTUREACCESS_STREAMING, width, height);
                    216:     SDL_SetTextureBlendMode(uiTexture, SDL_BLENDMODE_BLEND);
                    217:     
                    218:     fbTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_UNKNOWN, SDL_TEXTUREACCESS_STREAMING, width, height);
                    219:     SDL_SetTextureBlendMode(fbTexture, SDL_BLENDMODE_NONE);
                    220:     
                    221:     Uint32 format;
                    222:     int    d;
                    223:     SDL_QueryTexture(uiTexture, &format, &d, &d, &d);
                    224:     SDL_PixelFormatEnumToMasks(format, &d, &r, &g, &b, &a);
                    225:     mask = g | a;
                    226:     sdlscrn  = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32, r, g, b, a);
                    227:     uiBuffer = malloc(sdlscrn->h * sdlscrn->pitch);
                    228:     // clear UI with mask
                    229:     SDL_FillRect(sdlscrn, NULL, mask);
                    230:     
                    231:     /* Exit if we can not open a screen */
                    232:     if (!sdlscrn) {
                    233:         fprintf(stderr, "Could not set video mode:\n %s\n", SDL_GetError() );
                    234:         SDL_Quit();
                    235:         exit(-2);
                    236:     }
                    237:     
                    238:     if (!bInFullScreen) {
                    239:         /* re-embed the new SDL window */
                    240:         Control_ReparentWindow(width, height, bInFullScreen);
                    241:     }
                    242:     
                    243:     Statusbar_Init(sdlscrn);
                    244:     
                    245:        if (bGrabMouse) {
                    246:                SDL_SetRelativeMouseMode(SDL_TRUE);
                    247:         SDL_SetWindowGrab(sdlWindow, SDL_TRUE);
                    248:     }
                    249: 
                    250:        /* Configure some SDL stuff: */
                    251:        SDL_ShowCursor(SDL_DISABLE);
                    252:     
                    253:     /* Setup lookup tables */
                    254:     SDL_PixelFormat* pformat = SDL_AllocFormat(format);
                    255:     /* initialize BW lookup table */
                    256:     for(int i = 0; i < 0x100; i++) {
                    257:         BW2RGB[i*4+0] = bw2rgb(pformat, i>>6);
                    258:         BW2RGB[i*4+1] = bw2rgb(pformat, i>>4);
                    259:         BW2RGB[i*4+2] = bw2rgb(pformat, i>>2);
                    260:         BW2RGB[i*4+3] = bw2rgb(pformat, i>>0);
                    261:     }
                    262:     /* initialize color lookup table */
                    263:     for(int i = 0; i < 0x10000; i++)
                    264:         COL2RGB[SDL_BYTEORDER == SDL_BIG_ENDIAN ? i : SDL_Swap16(i)] = col2rgb(pformat, i);
                    265:     
                    266:     /* Initialization done -> signal */
                    267:     SDL_SemPost(initLatch);
                    268:     
                    269:     /* Enter repaint loop */
                    270:     while(doRepaint) {
                    271:         SDL_RenderClear(sdlRenderer);
                    272:         
                    273:         // Blit the NeXT framebuffer to textrue
                    274:         blitScreen(fbTexture);
                    275:         // Render NeXT framebuffer texture
                    276:         SDL_RenderCopy(sdlRenderer, fbTexture, NULL, NULL);
                    277:         
                    278:         // Copy UI surface to texture
                    279:         if(SDL_AtomicSet(&blitUI, 0)) {
                    280:             // update UI texture
                    281:             SDL_AtomicLock(&uiBufferLock);
                    282:             SDL_UpdateTexture(uiTexture, NULL, uiBuffer, sdlscrn->pitch);
                    283:             SDL_AtomicUnlock(&uiBufferLock);
                    284:         } else if(SDL_AtomicSet(&blitStatusBar, 0)) {
                    285:             SDL_LockSurface(sdlscrn);
                    286:             SDL_UpdateTexture(uiTexture, &statusBar, &((Uint8*)sdlscrn->pixels)[statusBar.y*sdlscrn->pitch], sdlscrn->pitch);
                    287:             SDL_UnlockSurface(sdlscrn);
                    288:         }
                    289:         // Render UI texture
                    290:         SDL_RenderCopy(sdlRenderer, uiTexture, NULL, NULL);
                    291:         
                    292:         // SDL_RenderPresent sleeps until next VSYNC because of SDL_RENDERER_PRESENTVSYNC in ScreenInit
                    293:         SDL_RenderPresent(sdlRenderer);
                    294:     }
                    295:     return 0;
                    296: }
                    297: 
                    298: /*-----------------------------------------------------------------------*/
                    299: /**
                    300:  * Init Screen, creates window and starts repatin thread
                    301:  */
                    302: void Screen_Init(void) {
                    303:     /* Set initial window resolution */
                    304:     bInFullScreen = ConfigureParams.Screen.bFullScreen;
                    305:     nScreenZoomX  = 1;
                    306:     nScreenZoomY  = 1;
                    307: 
                    308:     int width  = 1120;
                    309:     int height = 832;
                    310:     int sBarHeight, bitCount, maxW, maxH;
                    311:     
                    312:     /* Statusbar height for doubled screen size */
                    313:     sBarHeight = Statusbar_GetHeightForSize(1120, 832);
                    314:     Resolution_GetLimits(&maxW, &maxH, &bitCount);
                    315:     height += Statusbar_SetHeight(width, height);
                    316:     
                    317:     if (bInFullScreen) {
                    318:         /* unhide the WM window for fullscreen */
                    319:         Control_ReparentWindow(width, height, bInFullScreen);
                    320:     }
                    321:     
                    322:     /* Set new video mode */
                    323:     SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
                    324:     
                    325:     fprintf(stderr, "SDL screen request: %d x %d @ %d (%s)\n", width, height, bitCount, bInFullScreen ? "fullscreen" : "windowed");
                    326:     
                    327:     int x = SDL_WINDOWPOS_UNDEFINED;
                    328:     if(ConfigureParams.Screen.nMonitorType == MONITOR_TYPE_DUAL) {
                    329:         for(int i = 0; i < SDL_GetNumVideoDisplays(); i++) {
                    330:             SDL_Rect r;
                    331:             SDL_GetDisplayBounds(i, &r);
                    332:             if(r.w >= width * 2) {
                    333:                 x = r.x + width + ((r.w - width * 2) / 2);
                    334:                 break;
                    335:             }
                    336:             if(r.x >= 0 && SDL_GetNumVideoDisplays() == 1) x = r.x + 8;
                    337:         }
                    338:     }
                    339:     sdlWindow  = SDL_CreateWindow(PROG_NAME, x, SDL_WINDOWPOS_UNDEFINED, width, height, 0);
                    340:     if (!sdlWindow) {
                    341:         fprintf(stderr,"Failed to create window: %s!\n", SDL_GetError());
                    342:         exit(-1);
                    343:     }
                    344: 
                    345:     initLatch     = SDL_CreateSemaphore(0);
                    346:     repaintThread = SDL_CreateThread(repainter, "[Previous] screen repaint", NULL);
                    347:     SDL_SemWait(initLatch);
                    348: }
                    349: 
                    350: extern void nd_sdl_destroy();
                    351: 
                    352: /*-----------------------------------------------------------------------*/
                    353: /**
                    354:  * Free screen bitmap and allocated resources
                    355:  */
                    356: void Screen_UnInit(void) {
                    357:     doRepaint = false; // stop repaint thread
                    358:     int s;
                    359:     SDL_WaitThread(repaintThread, &s);
                    360:     nd_sdl_destroy();
                    361: }
                    362: 
                    363: /*-----------------------------------------------------------------------*/
                    364: /**
                    365:  * Enter Full screen mode
                    366:  */
                    367: void Screen_EnterFullScreen(void) {
                    368:        bool bWasRunning;
                    369: 
                    370:        if (!bInFullScreen) {
                    371:                /* Hold things... */
                    372:                bWasRunning = Main_PauseEmulation(false);
                    373:                bInFullScreen = true;
                    374: 
                    375:         SDL_GetWindowPosition(sdlWindow, &saveWindowBounds.x, &saveWindowBounds.y);
                    376:         SDL_GetWindowSize(sdlWindow, &saveWindowBounds.w, &saveWindowBounds.h);
                    377:         SDL_SetWindowFullscreen(sdlWindow, SDL_WINDOW_FULLSCREEN_DESKTOP);
                    378:                SDL_Delay(20);                  /* To give monitor time to change to new resolution */
                    379:                
                    380:                if (bWasRunning) {
                    381:                        /* And off we go... */
                    382:                        Main_UnPauseEmulation();
                    383:                }
                    384:                SDL_SetRelativeMouseMode(SDL_TRUE);
                    385:         SDL_SetWindowGrab(sdlWindow, SDL_TRUE);
                    386:        }
                    387: }
                    388: 
                    389: /*-----------------------------------------------------------------------*/
                    390: /**
                    391:  * Return from Full screen mode back to a window
                    392:  */
                    393: void Screen_ReturnFromFullScreen(void) {
                    394:        bool bWasRunning;
                    395: 
                    396:        if (bInFullScreen) {
                    397:                /* Hold things... */
                    398:                bWasRunning = Main_PauseEmulation(false);
                    399:                bInFullScreen = false;
                    400: 
                    401:         SDL_SetWindowFullscreen(sdlWindow, 0);
                    402:                SDL_Delay(20);                /* To give monitor time to switch resolution */
                    403:         SDL_SetWindowPosition(sdlWindow, saveWindowBounds.x, saveWindowBounds.y);
                    404:         SDL_SetWindowSize(sdlWindow, saveWindowBounds.w, saveWindowBounds.h);
                    405:         
                    406:                if (bWasRunning) {
                    407:                        /* And off we go... */
                    408:                        Main_UnPauseEmulation();
                    409:                }
                    410: 
                    411:                if (!bGrabMouse) {
                    412:                        /* Un-grab mouse pointer in windowed mode */
                    413:                        SDL_SetRelativeMouseMode(SDL_FALSE);
                    414:             SDL_SetWindowGrab(sdlWindow, SDL_FALSE);
                    415:                }
                    416:        }
                    417: }
                    418: 
                    419: /*-----------------------------------------------------------------------*/
                    420: /**
                    421:  * Force things associated with changing between low/medium/high res.
                    422:  */
                    423: void Screen_ModeChanged(void) {
                    424:        if (!sdlscrn) {
                    425:                /* screen not yet initialized */
                    426:                return;
                    427:        }
                    428:        if (bInFullScreen || bGrabMouse) {
                    429:                SDL_SetRelativeMouseMode(SDL_TRUE);
                    430:         SDL_SetWindowGrab(sdlWindow, SDL_TRUE);
                    431:        } else {
                    432:                SDL_SetRelativeMouseMode(SDL_FALSE);
                    433:         SDL_SetWindowGrab(sdlWindow, SDL_FALSE);
                    434:     }
                    435: }
                    436: 
                    437: /*-----------------------------------------------------------------------*/
                    438: /**
                    439:  * Draw screen to window/full-screen - (SC) empty. Screen re-draw is done in repaint thread.
                    440:  */
                    441: bool Screen_Draw(void) {
                    442:     
                    443:     Statusbar_OverlayBackup(sdlscrn);
                    444:     Statusbar_Update(sdlscrn);
                    445: 
                    446:     return !bQuitProgram;
                    447: }
                    448: 
                    449: static void uiUpdate() {
                    450:     SDL_LockSurface(sdlscrn);
                    451:     int     count = sdlscrn->w * sdlscrn->h;
                    452:     Uint32* dst   = (Uint32*)uiBuffer;
                    453:     Uint32* src   = (Uint32*)sdlscrn->pixels;
                    454:     SDL_AtomicLock(&uiBufferLock);
                    455:     // poor man's green-screen - would be nice if SDL had more blending modes...
                    456:     for(int i = count; --i >= 0; src++)
                    457:         *dst++ = *src == mask ? 0 : *src;
                    458:     SDL_AtomicUnlock(&uiBufferLock);
                    459:     SDL_UnlockSurface(sdlscrn);
                    460:     SDL_AtomicSet(&blitUI, 1);
                    461: }
                    462: 
                    463: void SDL_UpdateRects(SDL_Surface *screen, int numrects, SDL_Rect *rects) {
                    464:     while(numrects--) {
                    465:         if(rects->y < 832) {
                    466:             uiUpdate();
                    467:             doUIblit = true;
                    468:         } else {
                    469:             if(doUIblit) {
                    470:                 uiUpdate();
                    471:                 doUIblit = false;
                    472:             } else {
                    473:                 SDL_AtomicSet(&blitStatusBar, 1);
                    474:             }
                    475:         }
                    476:     }
                    477: }
                    478: 
                    479: void SDL_UpdateRect(SDL_Surface *screen, Sint32 x, Sint32 y, Sint32 w, Sint32 h) {
                    480:     SDL_Rect rect = { x, y, w, h };
                    481:     SDL_UpdateRects(screen, 1, &rect);
                    482: }
                    483: 
                    484: /*-----------------------------------------------------------------------*/
                    485: /**
                    486:  * Reset screen - (SC) unused
                    487:  */
                    488: void Screen_Reset(void) {}
                    489: 
                    490: /*-----------------------------------------------------------------------*/
                    491: /**
                    492:  * Set flags so screen will be TOTALLY re-drawn (clears whole of full-screen)
                    493:  * next time around - (SC) unused
                    494:  */
                    495: void Screen_SetFullUpdate(void) {}
                    496: 
                    497: #endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.