--- hatari/src/falcon/hostscreen.c 2019/04/09 08:47:21 1.1.1.4 +++ hatari/src/falcon/hostscreen.c 2019/04/09 08:49:37 1.1.1.6 @@ -10,6 +10,7 @@ */ const char HostScreen_fileid[] = "Hatari hostscreen.c : " __DATE__ " " __TIME__; +#include #include "main.h" #include "configuration.h" #include "control.h" @@ -17,6 +18,7 @@ const char HostScreen_fileid[] = "Hatari #include "stMemory.h" #include "ioMem.h" #include "hostscreen.h" +#include "resolution.h" #include "screen.h" #include "statusbar.h" @@ -47,42 +49,36 @@ const char HostScreen_fileid[] = "Hatari #define RGB_WHITE 0xffff00ff -static SDL_Surface *mainSurface; // The main window surface -static SDL_Surface *surf; // pointer to actual surface - - +/* TODO: put these hostscreen globals to some struct */ static Uint32 sdl_videoparams; -static Uint32 hs_width, hs_height, hs_bpp; +static int hs_width, hs_height, hs_width_req, hs_height_req, hs_bpp; static bool doUpdate; // the HW surface is available -> the SDL need not to update the surface after ->pixel access +static void HostScreen_remapPalette(void); + static struct { // TOS palette (bpp < 16) to SDL color mapping SDL_Color standard[256]; Uint32 native[256]; } palette; -static const unsigned long default_palette[] = { +static const Uint32 default_palette[] = { RGB_WHITE, RGB_RED, RGB_GREEN, RGB_YELLOW, RGB_BLUE, RGB_MAGENTA, RGB_CYAN, RGB_LTGRAY, RGB_GRAY, RGB_LTRED, RGB_LTGREEN, RGB_LTYELLOW, RGB_LTBLUE, RGB_LTMAGENTA, RGB_LTCYAN, RGB_BLACK }; -static int HostScreen_selectVideoMode(SDL_Rect **modes, Uint32 *width, Uint32 *height); -static void HostScreen_searchVideoMode( Uint32 *width, Uint32 *height, Uint32 *bpp ); - void HostScreen_Init(void) { int i; - for(i=0; i<256; i++) { - unsigned long color = default_palette[i%16]; + for(i = 0; i < 256; i++) { + Uint32 color = default_palette[i%16]; palette.standard[i].r = color >> 24; palette.standard[i].g = (color >> 16) & 0xff; palette.standard[i].b = color & 0xff; } - - mainSurface=NULL; } void HostScreen_UnInit(void) @@ -93,224 +89,190 @@ void HostScreen_UnInit(void) void HostScreen_toggleFullScreen(void) { sdl_videoparams ^= SDL_FULLSCREEN; - if (sdl_videoparams & SDL_FULLSCREEN) { - /* un-embed the Hatari WM window for fullscreen */ - Control_ReparentWindow(hs_width, hs_height, true); - } - if(SDL_WM_ToggleFullScreen(mainSurface) == 0) { - // SDL_WM_ToggleFullScreen() did not work. - // We have to change video mode "by hand". - SDL_Surface *temp = SDL_ConvertSurface(mainSurface, mainSurface->format, - mainSurface->flags); - Dprintf(("toggleFullScreen: SDL_WM_ToggleFullScreen() not supported" - " -> using SDL_SetVideoMode()")); - if (temp == NULL) - Dprintf(("toggleFullScreen: Unable to save screen content.")); + Dprintf(("Fullscreen = %s, width = %d, height = %d, bpp = %d\n", + sdl_videoparams&SDL_FULLSCREEN?"true":"false", hs_width_req, hs_height_req, hs_bpp)); -#if 1 - HostScreen_setWindowSize(hs_width, hs_height, hs_bpp); -#else - mainSurface = SDL_SetVideoMode(width, height, bpp, sdl_videoparams); - if (mainSurface == NULL) - Dprintf(("toggleFullScreen: Unable to set new video mode.")); - if (mainSurface->format->BitsPerPixel <= 8) - SDL_SetColors(mainSurface, temp->format->palette->colors, 0, - temp->format->palette->ncolors); -#endif - - if (SDL_BlitSurface(temp, NULL, mainSurface, NULL) != 0) - Dprintf(("toggleFullScreen: Unable to restore screen content.")); - SDL_FreeSurface(temp); - - /* refresh the screen */ - HostScreen_update1(true); - } else { - if (!(sdl_videoparams & SDL_FULLSCREEN)) { - /* re-embed the new Hatari SDL window */ - Control_ReparentWindow(hs_width, hs_height, false); - } - } + HostScreen_setWindowSize(hs_width_req, hs_height_req, hs_bpp); + /* force screen redraw */ + HostScreen_update1(true); } -static int HostScreen_selectVideoMode(SDL_Rect **modes, Uint32 *width, Uint32 *height) + +void HostScreen_setWindowSize(int width, int height, int bpp) { - int i, bestw, besth; + int screenwidth, screenheight, maxw, maxh; + int scalex, scaley, sbarheight; - /* Search the smallest nearest mode */ - bestw = modes[0]->w; - besth = modes[0]->h; - for (i=0;modes[i]; ++i) { - if ((modes[i]->w >= *width) && (modes[i]->h >= *height)) { - if ((modes[i]->w < bestw) || (modes[i]->h < besth)) { - bestw = modes[i]->w; - besth = modes[i]->h; - } - } - } + if (bpp == 24) + bpp = 32; - *width = bestw; - *height = besth; - Dprintf(("hostscreen: video mode found: %dx%d\n",*width,*height)); - - return 1; -} - -static void HostScreen_searchVideoMode( Uint32 *width, Uint32 *height, Uint32 *bpp ) -{ - SDL_Rect **modes; - SDL_PixelFormat pixelformat; - int modeflags; - - /* Search in available modes the best suited */ - Dprintf(("hostscreen: video mode asked: %dx%dx%d\n",*width,*height,*bpp)); - - if ((*width == 0) || (*height == 0)) { - *width = 640; - *height = 480; - } - - /* Read available video modes */ - modeflags = 0 /*SDL_HWSURFACE | SDL_HWPALETTE*/; - if (bInFullScreen) - modeflags |= SDL_FULLSCREEN; - - /*--- Search a video mode with asked bpp ---*/ - if (*bpp != 0) { - pixelformat.BitsPerPixel = *bpp; - modes = SDL_ListModes(&pixelformat, modeflags); - if ((modes != (SDL_Rect **) 0) && (modes != (SDL_Rect **) -1)) { - Dprintf(("hostscreen: searching a good video mode (any bpp)\n")); - if (HostScreen_selectVideoMode(modes,width,height)) { - Dprintf(("hostscreen: video mode selected: %dx%dx%d\n",*width,*height,*bpp)); - return; - } + /* constrain size request to user's desktop size */ + Resolution_GetDesktopSize(&maxw, &maxh); + scalex = scaley = 1; + while (width > maxw*scalex) { + scalex *= 2; + } + while (height > maxh*scalex) { + scalex *= 2; + } + if (scalex * scaley > 1) { + fprintf(stderr, "WARNING: too large screen size %dx%d -> divided by %dx%d!\n", + width, height, scalex, scaley); + width /= scalex; + height /= scaley; + } + + Resolution_GetLimits(&maxw, &maxh, &bpp); + nScreenZoomX = nScreenZoomY = 1; + + if (ConfigureParams.Screen.bAspectCorrect) { + /* Falcon (and TT) pixel scaling factors seem to 2^x + * (quarter/half pixel, interlace/double line), so + * do aspect correction as 2's exponent. + */ + while (nScreenZoomX*width < height && + 2*nScreenZoomX*width < maxw) { + nScreenZoomX *= 2; } - } - - /*--- Search a video mode with any bpp ---*/ - modes = SDL_ListModes(NULL, modeflags); - if ((modes != (SDL_Rect **) 0) && (modes != (SDL_Rect **) -1)) { - Dprintf(("hostscreen: searching a good video mode\n")); - if (HostScreen_selectVideoMode(modes,width,height)) { - Dprintf(("hostscreen: video mode selected: %dx%dx%d\n",*width,*height,*bpp)); - return; + while (2*nScreenZoomY*height < width && + 2*nScreenZoomY*height < maxh) { + nScreenZoomY *= 2; + } + if (nScreenZoomX*nScreenZoomY > 2) { + fprintf(stderr, "WARNING: strange screen size %dx%d -> aspect corrected by %dx%d!\n", + width, height, nScreenZoomX, nScreenZoomY); } } - if (modes == (SDL_Rect **) 0) { - Dprintf(("hostscreen: No modes available\n")); - } - - if (modes == (SDL_Rect **) -1) { - /* Any mode available */ - Dprintf(("hostscreen: Any modes available\n")); + /* then select scale as close to target size as possible + * without having larger size than it + */ + scalex = maxw/(nScreenZoomX*width); + scaley = maxh/(nScreenZoomY*height); + if (scalex > 1 && scaley > 1) { + /* keep aspect ratio */ + if (scalex < scaley) { + nScreenZoomX *= scalex; + nScreenZoomY *= scalex; + } else { + nScreenZoomX *= scaley; + nScreenZoomY *= scaley; + } } - Dprintf(("hostscreen: video mode selected: %dx%dx%d\n",*width,*height,*bpp)); -} - -void HostScreen_setWindowSize( Uint32 width, Uint32 height, Uint32 bpp ) -{ - Uint32 screenheight; - - if (bpp == 24) - bpp = 32; + hs_width_req = width; + hs_height_req = height; + width *= nScreenZoomX; + height *= nScreenZoomY; + + /* get statusbar size for this screen size */ + sbarheight = Statusbar_GetHeightForSize(width, height); + screenheight = height + sbarheight; + screenwidth = width; + + /* get resolution corresponding to these */ + Resolution_Search(&screenwidth, &screenheight, &bpp); + /* re-calculate statusbar height for this resolution */ + sbarheight = Statusbar_SetHeight(screenwidth, screenheight-sbarheight); - nScreenZoomX = 1; - nScreenZoomY = 1; - if (ConfigureParams.Screen.bZoomLowRes) + hs_bpp = bpp; + /* videl.c might scale things differently in fullscreen than + * in windowed mode because this uses screensize instead of using + * the aspect scaled sizes directly, but it works better this way. + */ + hs_width = screenwidth; + hs_height = screenheight - sbarheight; + + if (sdlscrn && (!bpp || sdlscrn->format->BitsPerPixel == bpp) && + sdlscrn->w == (signed)screenwidth && sdlscrn->h == (signed)screenheight && + (sdlscrn->flags&SDL_FULLSCREEN) == (sdl_videoparams&SDL_FULLSCREEN)) { - /* Ugly: 400x300 threshold is currently hard-coded. */ - /* Should rather be selectable by the user! */ - if (width && width <= 400) - { - nScreenZoomX = (800/width); - width *= nScreenZoomX; - } - if (height && height <= 300) - { - nScreenZoomY = (550/height); - height *= nScreenZoomY; + /* same host screen size despite Atari resolution change, + * -> no time consuming host video mode change needed + */ + if (screenwidth > width || screenheight > height+sbarheight) { + /* Atari screen smaller than host -> clear screen */ + SDL_Rect rect; + rect.x = 0; + rect.y = 0; + rect.w = sdlscrn->w; + rect.h = sdlscrn->h - sbarheight; + SDL_FillRect(sdlscrn, &rect, SDL_MapRGB(sdlscrn->format, 0, 0, 0)); + /* re-calculate variables in case height + statusbar height + * don't anymore match SDL surface size (there's an assert + * for that) + */ + Statusbar_Init(sdlscrn); } + // check in case switched from VDI to Hostscreen + doUpdate = ( sdlscrn->flags & SDL_HWSURFACE ) == 0; + return; } - screenheight = height + Statusbar_SetHeight(width, height); - - // Select a correct video mode - HostScreen_searchVideoMode(&width, &screenheight, &bpp); - hs_width = width; - hs_height = height; - hs_bpp = bpp; - - // SelectVideoMode(); if (bInFullScreen) { /* un-embed the Hatari WM window for fullscreen */ - Control_ReparentWindow(width, screenheight, bInFullScreen); + Control_ReparentWindow(screenwidth, screenheight, bInFullScreen); sdl_videoparams = SDL_SWSURFACE|SDL_HWPALETTE|SDL_FULLSCREEN; } else { sdl_videoparams = SDL_SWSURFACE|SDL_HWPALETTE; } - mainSurface = SDL_SetVideoMode(width, screenheight, bpp, sdl_videoparams); +#ifdef _MUDFLAP + if (sdlscrn) { + __mf_unregister(sdlscrn->pixels, sdlscrn->pitch*sdlscrn->h, __MF_TYPE_GUESS); + } +#endif + sdlscrn = SDL_SetVideoMode(screenwidth, screenheight, bpp, sdl_videoparams); +#ifdef _MUDFLAP + __mf_register(sdlscrn->pixels, sdlscrn->pitch*sdlscrn->h, __MF_TYPE_GUESS, "SDL pixels"); +#endif if (!bInFullScreen) { /* re-embed the new Hatari SDL window */ - Control_ReparentWindow(width, screenheight, bInFullScreen); + Control_ReparentWindow(screenwidth, screenheight, bInFullScreen); } - sdlscrn = surf = mainSurface; - // update the surface's palette - HostScreen_updatePalette( 256 ); + // In case surface format changed, update SDL palette & remap the native palette + HostScreen_updatePalette(256); + HostScreen_remapPalette(); - Statusbar_Init(mainSurface); + // redraw statusbar + Statusbar_Init(sdlscrn); - Dprintf(("Surface Pitch = %d, width = %d, height = %d\n", surf->pitch, surf->w, surf->h)); - Dprintf(("Must Lock? %s\n", SDL_MUSTLOCK(surf) ? "YES" : "NO")); + Dprintf(("Surface Pitch = %d, width = %d, height = %d\n", sdlscrn->pitch, sdlscrn->w, sdlscrn->h)); + Dprintf(("Must Lock? %s\n", SDL_MUSTLOCK(sdlscrn) ? "YES" : "NO")); // is the SDL_update needed? - doUpdate = ( surf->flags & SDL_HWSURFACE ) == 0; - - HostScreen_renderBegin(); - -// VideoRAMBaseHost = (uint8 *) surf->pixels; -// InitVMEMBaseDiff(VideoRAMBaseHost, VideoRAMBase); -// Dprintf(("VideoRAM starts at %p (%08x)\n", VideoRAMBaseHost, VideoRAMBase)); - Dprintf(("surf->pixels = %p, getVideoSurface() = %p\n", - surf->pixels, SDL_GetVideoSurface()->pixels)); - - HostScreen_renderEnd(); + doUpdate = ( sdlscrn->flags & SDL_HWSURFACE ) == 0; Dprintf(("Pixel format:bitspp=%d, tmasks r=%04x g=%04x b=%04x" ", tshifts r=%d g=%d b=%d" ", tlosses r=%d g=%d b=%d\n", - surf->format->BitsPerPixel, - surf->format->Rmask, surf->format->Gmask, surf->format->Bmask, - surf->format->Rshift, surf->format->Gshift, surf->format->Bshift, - surf->format->Rloss, surf->format->Gloss, surf->format->Bloss)); + sdlscrn->format->BitsPerPixel, + sdlscrn->format->Rmask, sdlscrn->format->Gmask, sdlscrn->format->Bmask, + sdlscrn->format->Rshift, sdlscrn->format->Gshift, sdlscrn->format->Bshift, + sdlscrn->format->Rloss, sdlscrn->format->Gloss, sdlscrn->format->Bloss)); + + Main_WarpMouse(sdlscrn->w/2,sdlscrn->h/2); } -static void HostScreen_update5(Sint32 x, Sint32 y, Sint32 w, Sint32 h, bool forced) +void HostScreen_update1(bool forced) { if ( !forced && !doUpdate ) // the HW surface is available return; - SDL_UpdateRect(mainSurface, x, y, w, h); -} - -void HostScreen_update1(bool forced) -{ - HostScreen_update5( 0, 0, hs_width, hs_height, forced ); + SDL_UpdateRect( sdlscrn, 0, 0, hs_width, hs_height ); } Uint32 HostScreen_getBpp(void) { - return surf->format->BytesPerPixel; + return sdlscrn->format->BytesPerPixel; } Uint32 HostScreen_getPitch(void) { - return surf->pitch; + return sdlscrn->pitch; } Uint32 HostScreen_getWidth(void) @@ -325,17 +287,22 @@ Uint32 HostScreen_getHeight(void) Uint8 *HostScreen_getVideoramAddress(void) { - return surf->pixels; /* FIXME maybe this should be mainSurface? */ + return sdlscrn->pixels; } -void HostScreen_setPaletteColor(Uint8 idx, Uint32 red, Uint32 green, Uint32 blue) +SDL_PixelFormat *HostScreen_getFormat(void) +{ + return sdlscrn->format; +} + +void HostScreen_setPaletteColor(Uint8 idx, Uint8 red, Uint8 green, Uint8 blue) { // set the SDL standard RGB palette settings palette.standard[idx].r = red; palette.standard[idx].g = green; palette.standard[idx].b = blue; // convert the color to native - palette.native[idx] = SDL_MapRGB( surf->format, red, green, blue ); + palette.native[idx] = SDL_MapRGB( sdlscrn->format, red, green, blue ); } Uint32 HostScreen_getPaletteColor(Uint8 idx) @@ -343,21 +310,27 @@ Uint32 HostScreen_getPaletteColor(Uint8 return palette.native[idx]; } -void HostScreen_updatePalette(Uint16 colorCount) +void HostScreen_updatePalette(int colorCount) { - SDL_SetColors( surf, palette.standard, 0, colorCount ); + SDL_SetColors( sdlscrn, palette.standard, 0, colorCount ); } -Uint32 HostScreen_getColor(Uint32 red, Uint32 green, Uint32 blue) +static void HostScreen_remapPalette(void) { - return SDL_MapRGB( surf->format, red, green, blue ); -} + int i; + Uint32 *native = palette.native; + SDL_Color *standard = palette.standard; + SDL_PixelFormat *fmt = sdlscrn->format; + for(i = 0; i < 256; i++, native++, standard++) { + *native = SDL_MapRGB(fmt, standard->r, standard->g, standard->b); + } +} bool HostScreen_renderBegin(void) { - if (SDL_MUSTLOCK(surf)) - if (SDL_LockSurface(surf) < 0) { + if (SDL_MUSTLOCK(sdlscrn)) + if (SDL_LockSurface(sdlscrn) < 0) { printf("Couldn't lock surface to refresh!\n"); return false; } @@ -367,7 +340,7 @@ bool HostScreen_renderBegin(void) void HostScreen_renderEnd(void) { - if (SDL_MUSTLOCK(surf)) - SDL_UnlockSurface(surf); - Statusbar_Update(surf); + if (SDL_MUSTLOCK(sdlscrn)) + SDL_UnlockSurface(sdlscrn); + Statusbar_Update(sdlscrn); }