--- previous/src/fast_screen.c 2018/04/24 19:29:48 1.1.1.1 +++ previous/src/fast_screen.c 2018/04/24 19:33:09 1.1.1.3 @@ -4,51 +4,51 @@ This file is distributed under the GNU Public License, version 2 or at your option any later version. Read the file gpl.txt for details. - (SC) Simon Schubiger - most of it rewritten for Previous NeXT emualtor + (SC) Simon Schubiger - most of it rewritten for Previous NeXT emulator */ #include #include #include -#if 0 -void blitDimension(SDL_Texture* tex) {} -#include "screen.c" -#else - const char Screen_fileid[] = "Previous fast_screen.c : " __DATE__ " " __TIME__; #include "main.h" #include "configuration.h" #include "log.h" #include "m68000.h" -#include "dimension.h" +#include "dimension.hpp" +#include "nd_mem.hpp" #include "paths.h" #include "screen.h" -#include "control.h" -#include "convert/routines.h" -#include "resolution.h" #include "statusbar.h" #include "video.h" -SDL_Window* sdlWindow; -SDL_Surface* sdlscrn = NULL; /* The SDL screen surface */ -int nScreenZoomX, nScreenZoomY;/* Zooming factors, used for scaling mouse motions */ - -/* extern for shortcuts and falcon/hostscreen.c */ -volatile bool bGrabMouse = false; /* Grab the mouse cursor in the window */ -volatile bool bInFullScreen = false; /* true if in full screen */ +SDL_Window* sdlWindow; +SDL_Surface* sdlscrn = NULL; /* The SDL screen surface */ +int nScreenZoomX, nScreenZoomY; /* Zooming factors, used for scaling mouse motions */ + +/* extern for shortcuts */ +volatile bool bGrabMouse = false; /* Grab the mouse cursor in the window */ +volatile bool bInFullScreen = false; /* true if in full screen */ + +static const int NeXT_SCRN_WIDTH = 1120; +static const int NeXT_SCRN_HEIGHT = 832; static SDL_Thread* repaintThread; +static SDL_Renderer* sdlRenderer; static SDL_sem* initLatch; -static SDL_atomic_t blitUI; /* When value = 1, the repaint thread will blit the sldscrn surface to the screen on the next redraw */ -static SDL_atomic_t blitStatusBar; /* When value = 1, the repaint thread will blit the sldscrn status bar on the next redraw */ +static SDL_atomic_t blitFB; +static SDL_atomic_t blitUI; /* When value == 1, the repaint thread will blit the sldscrn surface to the screen on the next redraw */ static bool doUIblit; static SDL_Rect saveWindowBounds; /* Window bounds before going fullscreen. Used to restore window size & position. */ static void* uiBuffer; /* uiBuffer used for ui texture */ -static SDL_SpinLock uiBufferLock; /* Lock for concurrent access to UI buffer between main thread and repainter */ +static void* uiBufferTmp; /* Temporary uiBuffer used by repainter */ +static SDL_SpinLock uiBufferLock; /* Lock for concurrent access to UI buffer between m68k thread and repainter */ static Uint32 mask; /* green screen mask for transparent UI areas */ static volatile bool doRepaint = true; /* Repaint thread runs while true */ +static SDL_Rect statusBar; + static Uint32 BW2RGB[0x400]; static Uint32 COL2RGB[0x10000]; @@ -76,12 +76,12 @@ static Uint32 col2rgb(SDL_PixelFormat* f static void blitBW(SDL_Texture* tex) { void* pixels; int d; - int pitch = ConfigureParams.System.bTurbo ? 280 : 288; + int pitch = (NeXT_SCRN_WIDTH + (ConfigureParams.System.bTurbo ? 0 : 32)) / 4; SDL_LockTexture(tex, NULL, &pixels, &d); Uint32* dst = (Uint32*)pixels; - for(int y = 0; y < 832; y++) { + for(int y = 0; y < NeXT_SCRN_HEIGHT; y++) { int src = y * pitch; - for(int x = 0; x < 280; x++, src++) { + for(int x = 0; x < NeXT_SCRN_WIDTH/4; x++, src++) { int idx = NEXTVideo[src] * 4; *dst++ = BW2RGB[idx+0]; *dst++ = BW2RGB[idx+1]; @@ -98,92 +98,91 @@ static void blitBW(SDL_Texture* tex) { static void blitColor(SDL_Texture* tex) { void* pixels; int d; - int pitch = ConfigureParams.System.bTurbo ? 1120 : 1152; + int pitch = NeXT_SCRN_WIDTH + (ConfigureParams.System.bTurbo ? 0 : 32); SDL_LockTexture(tex, NULL, &pixels, &d); Uint32* dst = (Uint32*)pixels; - for(int y = 0; y < 832; y++) { + for(int y = 0; y < NeXT_SCRN_HEIGHT; y++) { Uint16* src = (Uint16*)NEXTColorVideo + (y*pitch); - for(int x = 0; x < 1120; x++) { + for(int x = 0; x < NeXT_SCRN_WIDTH; x++) { *dst++ = COL2RGB[*src++]; } } SDL_UnlockTexture(tex); } -extern - /* - Dimension format is 8bit per pixel, big-endian: RRGGGBBBA + Dimension format is 8bit per pixel, big-endian: RRGGBBAA */ -void blitDimension(SDL_Texture* tex) { -#if ENABLE_DIMENSION - Uint32* src = (Uint32*)&ND_vram[ND_vram_off]; - void* pixels; +void blitDimension(Uint32* vram, SDL_Texture* tex) { +#if ND_STEP + Uint32* src = &vram[0]; +#else + Uint32* src = &vram[16]; +#endif int d; Uint32 format; SDL_QueryTexture(tex, &format, &d, &d, &d); - SDL_LockTexture(tex, NULL, &pixels, &d); - Uint32* dst = (Uint32*)pixels; if(SDL_BYTEORDER == SDL_BIG_ENDIAN) { - /* Add big-endian accelerated blit loops as needed */ + /* Add big-endian accelerated blit loops as needed here */ switch (format) { default: { + void* pixels; + SDL_LockTexture(tex, NULL, &pixels, &d); + Uint32* dst = (Uint32*)pixels; + /* fallback to SDL_MapRGB */ SDL_PixelFormat* pformat = SDL_AllocFormat(format); - for(int y = 832; --y >= 0;) { - for(int x = 1120; --x >= 0;) { + for(int y = NeXT_SCRN_HEIGHT; --y >= 0;) { + for(int x = NeXT_SCRN_WIDTH; --x >= 0;) { Uint32 v = *src++; - *dst++ = SDL_MapRGB(pformat, (v >> 24) & 0xFF, (v>>16) & 0xFF, (v>>8) & 0xFF); + *dst++ = SDL_MapRGB(pformat, (v >> 8) & 0xFF, (v>>16) & 0xFF, (v>>24) & 0xFF); } - src += 1152 - 1120; + src += 32; } SDL_FreeFormat(pformat); + SDL_UnlockTexture(tex); break; } } } else { - /* Add little-endian accelerated blit loops as needed */ + /* Add little-endian accelerated blit loops as needed here */ switch (format) { - case SDL_PIXELFORMAT_ARGB8888: - for(int y = 832; --y >= 0;) { - for(int x = 1120; --x >= 0;) { - // Uint32 LE: AABBGGRR - // Target: AARRGGBB - Uint32 v = *src++; - *dst++ = (v & 0xFF000000) | ((v<<16) &0x00FF0000) | (v &0x0000FF00) | ((v>>16) &0x000000FF); - } - src += 1152 - 1120; - } + case SDL_PIXELFORMAT_ARGB8888: { + SDL_UpdateTexture(tex, NULL, src, (NeXT_SCRN_WIDTH+32)*4); break; + } default: { + void* pixels; + SDL_LockTexture(tex, NULL, &pixels, &d); + Uint32* dst = (Uint32*)pixels; + /* fallback to SDL_MapRGB */ SDL_PixelFormat* pformat = SDL_AllocFormat(format); - for(int y = 832; --y >= 0;) { - for(int x = 1120; --x >= 0;) { - Uint32 v = SDL_Swap32(*src++); - *dst++ = SDL_MapRGB(pformat, (v >> 24) & 0xFF, (v>>16) & 0xFF, (v>>8) & 0xFF); + for(int y = NeXT_SCRN_HEIGHT; --y >= 0;) { + for(int x = NeXT_SCRN_WIDTH; --x >= 0;) { + Uint32 v = *src++; + *dst++ = SDL_MapRGB(pformat, (v >> 16) & 0xFF, (v>>8) & 0xFF, (v>>0) & 0xFF); } - src += 1152 - 1120; + src += 32; } SDL_FreeFormat(pformat); + SDL_UnlockTexture(tex); break; } } } - SDL_UnlockTexture(tex); -#endif } /* Blit NeXT framebuffer to texture. */ static void blitScreen(SDL_Texture* tex) { -#if ENABLE_DIMENSION if (ConfigureParams.Screen.nMonitorType==MONITOR_TYPE_DIMENSION) { - blitDimension(tex); + Uint32* vram = nd_vram_for_slot(ND_SLOT(ConfigureParams.Screen.nMonitorNum)); + if(vram) + blitDimension(vram, tex); return; } -#endif if(ConfigureParams.System.bColor) { blitColor(tex); } else { @@ -192,26 +191,30 @@ static void blitScreen(SDL_Texture* tex) } /* - Initializes sdl graphics and the enter repaint loop. - Loop: blits the NeXT framebuffer to the fbTexture, blends with the GUI surface and + Initializes SDL graphics and then enters repaint loop. + Loop: Blits the NeXT framebuffer to the fbTexture, blends with the GUI surface and shows it. */ static int repainter(void* unused) { int width; int height; + SDL_SetThreadPriority(SDL_THREAD_PRIORITY_NORMAL); SDL_GetWindowSize(sdlWindow, &width, &height); - SDL_Renderer* sdlRenderer; + statusBar.x = 0; + statusBar.y = NeXT_SCRN_HEIGHT; + statusBar.w = width; + statusBar.h = height - NeXT_SCRN_HEIGHT; + SDL_Texture* uiTexture; SDL_Texture* fbTexture; - SDL_Rect statusBar = {0,832,width,height-832}; Uint32 r, g, b, a; sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); SDL_RenderSetLogicalSize(sdlRenderer, width, height); - + uiTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_UNKNOWN, SDL_TEXTUREACCESS_STREAMING, width, height); SDL_SetTextureBlendMode(uiTexture, SDL_BLENDMODE_BLEND); @@ -223,8 +226,9 @@ static int repainter(void* unused) { SDL_QueryTexture(uiTexture, &format, &d, &d, &d); SDL_PixelFormatEnumToMasks(format, &d, &r, &g, &b, &a); mask = g | a; - sdlscrn = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32, r, g, b, a); - uiBuffer = malloc(sdlscrn->h * sdlscrn->pitch); + sdlscrn = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32, r, g, b, a); + uiBuffer = malloc(sdlscrn->h * sdlscrn->pitch); + uiBufferTmp = malloc(sdlscrn->h * sdlscrn->pitch); // clear UI with mask SDL_FillRect(sdlscrn, NULL, mask); @@ -235,11 +239,6 @@ static int repainter(void* unused) { exit(-2); } - if (!bInFullScreen) { - /* re-embed the new SDL window */ - Control_ReparentWindow(width, height, bInFullScreen); - } - Statusbar_Init(sdlscrn); if (bGrabMouse) { @@ -266,38 +265,63 @@ static int repainter(void* unused) { /* Initialization done -> signal */ SDL_SemPost(initLatch); + /* Start with framebuffer blit enabled */ + SDL_AtomicSet(&blitFB, 1); + /* Enter repaint loop */ while(doRepaint) { - SDL_RenderClear(sdlRenderer); + bool updateFB = false; + bool updateUI = false; - // Blit the NeXT framebuffer to textrue - blitScreen(fbTexture); - // Render NeXT framebuffer texture - SDL_RenderCopy(sdlRenderer, fbTexture, NULL, NULL); + if (SDL_AtomicGet(&blitFB)) { + // Blit the NeXT framebuffer to textrue + blitScreen(fbTexture); + updateFB = true; + } // Copy UI surface to texture + SDL_AtomicLock(&uiBufferLock); if(SDL_AtomicSet(&blitUI, 0)) { - // update UI texture - SDL_AtomicLock(&uiBufferLock); - SDL_UpdateTexture(uiTexture, NULL, uiBuffer, sdlscrn->pitch); - SDL_AtomicUnlock(&uiBufferLock); - } else if(SDL_AtomicSet(&blitStatusBar, 0)) { - SDL_LockSurface(sdlscrn); - SDL_UpdateTexture(uiTexture, &statusBar, &((Uint8*)sdlscrn->pixels)[statusBar.y*sdlscrn->pitch], sdlscrn->pitch); - SDL_UnlockSurface(sdlscrn); + // update full UI texture + memcpy(uiBufferTmp, uiBuffer, sdlscrn->h * sdlscrn->pitch); + updateUI = true; + } + SDL_AtomicUnlock(&uiBufferLock); + + if(updateUI) { + SDL_UpdateTexture(uiTexture, NULL, uiBufferTmp, sdlscrn->pitch); } - // Render UI texture - SDL_RenderCopy(sdlRenderer, uiTexture, NULL, NULL); - // SDL_RenderPresent sleeps until next VSYNC because of SDL_RENDERER_PRESENTVSYNC in ScreenInit - SDL_RenderPresent(sdlRenderer); + // Update and render UI texture + if (updateFB || updateUI) { + SDL_RenderClear(sdlRenderer); + // Render NeXT framebuffer texture + SDL_RenderCopy(sdlRenderer, fbTexture, NULL, NULL); + SDL_RenderCopy(sdlRenderer, uiTexture, NULL, NULL); + // SDL_RenderPresent sleeps until next VSYNC because of SDL_RENDERER_PRESENTVSYNC in ScreenInit + SDL_RenderPresent(sdlRenderer); + } else { + host_sleep_ms(10); + } } return 0; } /*-----------------------------------------------------------------------*/ /** - * Init Screen, creates window and starts repatin thread + * Pause Screen, pauses or resumes drawing of NeXT framebuffer + */ +void Screen_Pause(bool pause) { + if (pause) { + SDL_AtomicSet(&blitFB, 0); + } else { + SDL_AtomicSet(&blitFB, 1); + } +} + +/*-----------------------------------------------------------------------*/ +/** + * Init Screen, creates window and starts repaint thread */ void Screen_Init(void) { /* Set initial window resolution */ @@ -305,24 +329,16 @@ void Screen_Init(void) { nScreenZoomX = 1; nScreenZoomY = 1; - int width = 1120; - int height = 832; - int sBarHeight, bitCount, maxW, maxH; - - /* Statusbar height for doubled screen size */ - sBarHeight = Statusbar_GetHeightForSize(1120, 832); - Resolution_GetLimits(&maxW, &maxH, &bitCount); - height += Statusbar_SetHeight(width, height); + int width = NeXT_SCRN_WIDTH; + int height = NeXT_SCRN_HEIGHT; - if (bInFullScreen) { - /* unhide the WM window for fullscreen */ - Control_ReparentWindow(width, height, bInFullScreen); - } + /* Statusbar height */ + height += Statusbar_SetHeight(width, height); /* Set new video mode */ SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); - fprintf(stderr, "SDL screen request: %d x %d @ %d (%s)\n", width, height, bitCount, bInFullScreen ? "fullscreen" : "windowed"); + fprintf(stderr, "SDL screen request: %d x %d (%s)\n", width, height, bInFullScreen ? "fullscreen" : "windowed"); int x = SDL_WINDOWPOS_UNDEFINED; if(ConfigureParams.Screen.nMonitorType == MONITOR_TYPE_DUAL) { @@ -347,7 +363,7 @@ void Screen_Init(void) { SDL_SemWait(initLatch); } -extern void nd_sdl_destroy(); +void nd_sdl_destroy(void); /*-----------------------------------------------------------------------*/ /** @@ -418,7 +434,7 @@ void Screen_ReturnFromFullScreen(void) { /*-----------------------------------------------------------------------*/ /** - * Force things associated with changing between low/medium/high res. + * Force things associated with changing between fullscreen/windowed */ void Screen_ModeChanged(void) { if (!sdlscrn) { @@ -434,19 +450,40 @@ void Screen_ModeChanged(void) { } } + /*-----------------------------------------------------------------------*/ /** - * Draw screen to window/full-screen - (SC) empty. Screen re-draw is done in repaint thread. + * Draw screen to window/full-screen - (SC) Just status bar updates. Screen redraw is done in repaint thread. */ -bool Screen_Draw(void) { - + +static bool shieldStatusBarUpdate; + +static void statusBarUpdate(void) { + if(shieldStatusBarUpdate) return; + SDL_LockSurface(sdlscrn); + SDL_AtomicLock(&uiBufferLock); + memcpy(&((Uint8*)uiBuffer)[statusBar.y*sdlscrn->pitch], &((Uint8*)sdlscrn->pixels)[statusBar.y*sdlscrn->pitch], statusBar.h * sdlscrn->pitch); + SDL_AtomicSet(&blitUI, 1); + SDL_AtomicUnlock(&uiBufferLock); + SDL_UnlockSurface(sdlscrn); +} + +bool Update_StatusBar(void) { + shieldStatusBarUpdate = true; Statusbar_OverlayBackup(sdlscrn); Statusbar_Update(sdlscrn); + shieldStatusBarUpdate = false; + statusBarUpdate(); + return !bQuitProgram; } -static void uiUpdate() { +/* + Copy UI SDL surface to uiBuffer and replace mask pixels with transparent pixels for + UI blending with framebuffer texture. +*/ +static void uiUpdate(void) { SDL_LockSurface(sdlscrn); int count = sdlscrn->w * sdlscrn->h; Uint32* dst = (Uint32*)uiBuffer; @@ -455,14 +492,14 @@ static void uiUpdate() { // poor man's green-screen - would be nice if SDL had more blending modes... for(int i = count; --i >= 0; src++) *dst++ = *src == mask ? 0 : *src; + SDL_AtomicSet(&blitUI, 1); SDL_AtomicUnlock(&uiBufferLock); SDL_UnlockSurface(sdlscrn); - SDL_AtomicSet(&blitUI, 1); } void SDL_UpdateRects(SDL_Surface *screen, int numrects, SDL_Rect *rects) { while(numrects--) { - if(rects->y < 832) { + if(rects->y < NeXT_SCRN_HEIGHT) { uiUpdate(); doUIblit = true; } else { @@ -470,7 +507,7 @@ void SDL_UpdateRects(SDL_Surface *screen uiUpdate(); doUIblit = false; } else { - SDL_AtomicSet(&blitStatusBar, 1); + statusBarUpdate(); } } } @@ -480,18 +517,3 @@ void SDL_UpdateRect(SDL_Surface *screen, SDL_Rect rect = { x, y, w, h }; SDL_UpdateRects(screen, 1, &rect); } - -/*-----------------------------------------------------------------------*/ -/** - * Reset screen - (SC) unused - */ -void Screen_Reset(void) {} - -/*-----------------------------------------------------------------------*/ -/** - * Set flags so screen will be TOTALLY re-drawn (clears whole of full-screen) - * next time around - (SC) unused - */ -void Screen_SetFullUpdate(void) {} - -#endif \ No newline at end of file