DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/gui/render.cpp
00001 /*
00002  *  Copyright (C) 2002-2020  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License along
00015  *  with this program; if not, write to the Free Software Foundation, Inc.,
00016  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 
00020 #include <sys/types.h>
00021 #include <assert.h>
00022 #include <math.h>
00023 
00024 #include "dosbox.h"
00025 #include "video.h"
00026 #include "render.h"
00027 #include "setup.h"
00028 #include "control.h"
00029 #include "mapper.h"
00030 #include "cross.h"
00031 #include "hardware.h"
00032 #include "support.h"
00033 #include "sdlmain.h"
00034 
00035 #include "render_scalers.h"
00036 #if defined(__SSE__)
00037 #include <xmmintrin.h>
00038 #include <emmintrin.h>
00039 #endif
00040 
00041 Render_t                                render;
00042 Bitu                                    last_gfx_flags = 0;
00043 ScalerLineHandler_t                     RENDER_DrawLine;
00044 
00045 uint32_t                                GFX_palette32bpp[256] = {0};
00046 
00047 unsigned int                            GFX_GetBShift();
00048 void                                    RENDER_CallBack( GFX_CallBackFunctions_t function );
00049 
00050 static void Check_Palette(void) {
00051     /* Clean up any previous changed palette data */
00052     if (render.pal.changed) {
00053         memset(render.pal.modified, 0, sizeof(render.pal.modified));
00054         render.pal.changed = false;
00055     }
00056     if (render.pal.first>render.pal.last) 
00057         return;
00058     Bitu i;
00059     switch (render.scale.outMode) {
00060         case scalerMode8:
00061             GFX_SetPalette(render.pal.first,render.pal.last-render.pal.first+1,(GFX_PalEntry *)&render.pal.rgb[render.pal.first]);
00062             break;
00063         case scalerMode15:
00064         case scalerMode16:
00065             for (i=render.pal.first;i<=render.pal.last;i++) {
00066                 Bit8u r=render.pal.rgb[i].red;
00067                 Bit8u g=render.pal.rgb[i].green;
00068                 Bit8u b=render.pal.rgb[i].blue;
00069                 Bit16u newPal = (Bit16u)GFX_GetRGB(r,g,b);
00070                 if (newPal != render.pal.lut.b16[i]) {
00071                     render.pal.changed = true;
00072                     render.pal.modified[i] = 1;
00073                     render.pal.lut.b16[i] = newPal;
00074                 }
00075             }
00076             break;
00077         case scalerMode32:
00078         default:
00079             for (i=render.pal.first;i<=render.pal.last;i++) {
00080                 Bit8u r=render.pal.rgb[i].red;
00081                 Bit8u g=render.pal.rgb[i].green;
00082                 Bit8u b=render.pal.rgb[i].blue;
00083                 Bit32u newPal = (Bit32u)GFX_GetRGB(r,g,b);
00084                 if (newPal != render.pal.lut.b32[i]) {
00085                     render.pal.changed = true;
00086                     render.pal.modified[i] = 1;
00087                     render.pal.lut.b32[i] = newPal;
00088                 }
00089             }
00090             break;
00091     }
00092     /* Setup pal index to startup values */
00093     render.pal.first=256;
00094     render.pal.last=0;
00095 }
00096 
00097 void RENDER_SetPal(Bit8u entry,Bit8u red,Bit8u green,Bit8u blue) {
00098     if (GFX_GetBShift() == 0) {
00099         GFX_palette32bpp[entry] =
00100             ((uint32_t)red << (uint32_t)16) +
00101             ((uint32_t)green << (uint32_t)8) +
00102             ((uint32_t)blue << (uint32_t)0);
00103     }
00104     else {
00105         GFX_palette32bpp[entry] =
00106             ((uint32_t)blue << (uint32_t)16) +
00107             ((uint32_t)green << (uint32_t)8) +
00108             ((uint32_t)red << (uint32_t)0);
00109     }
00110 
00111     render.pal.rgb[entry].red=red;
00112     render.pal.rgb[entry].green=green;
00113     render.pal.rgb[entry].blue=blue;
00114     if (render.pal.first>entry) render.pal.first=entry;
00115     if (render.pal.last<entry) render.pal.last=entry;
00116 }
00117 
00118 static void RENDER_EmptyLineHandler(const void * src) {
00119     (void)src;//UNUSED
00120 }
00121 
00122 /*HACK*/
00123 #if defined(__SSE__) && (defined(_M_AMD64) || defined(__e2k__))
00124 # define sse2_available (1) /* SSE2 is always available on x86_64 and Elbrus */
00125 #else
00126 # ifdef __SSE__
00127 extern bool             sse1_available;
00128 extern bool             sse2_available;
00129 # endif
00130 #endif
00131 /*END HACK*/
00132 
00133 /* NTS: In normal conditions, the renderer at the start of the frame
00134  *      does not call the scaler but instead compares line by line
00135  *      from the cache. The instant a line differs, it switches to
00136  *      running the scaler for the rest of the frame and the scaler
00137  *      will compare pixels and process only those pixel groups that
00138  *      changed, and then send the scanline to the changed lines
00139  *      list.
00140  *
00141  *      If C_SCALER_FULL_LINE, the scaler will blindly process pixels
00142  *      without comparing to detect changes. This code changes to
00143  *      let the scaler blast pixels at least for some scan lines
00144  *      before switching back to comparing scan lines to determine
00145  *      whether more scaler processing is needed.
00146  *
00147  *      The intent of C_SCALER_FULL_LINE is to process the scalers
00148  *      in a way more appropriate for embedded systems where memory
00149  *      and video bandwidth are more limited. */
00150 
00151 static inline bool RENDER_DrawLine_scanline_cacheHit(const void *s) {
00152     if (s) {
00153         const Bitu *src = (Bitu*)s;
00154         Bitu *cache = (Bitu*)(render.scale.cacheRead);
00155         Bits count = (Bits)render.src.start;
00156 #if defined(__SSE__)
00157         if (sse2_available) {
00158 #define MY_SIZEOF_INT_P sizeof(*src)
00159             static const Bitu simd_inc = 16/MY_SIZEOF_INT_P;
00160             while (count >= (Bits)simd_inc) {
00161                 __m128i v = _mm_loadu_si128((const __m128i*)src);
00162                 __m128i c = _mm_loadu_si128((const __m128i*)cache);
00163                 __m128i cmp = _mm_cmpeq_epi32(v, c);
00164                 if (GCC_UNLIKELY(_mm_movemask_epi8(cmp) != 0xFFFF))
00165                     goto cacheMiss;
00166                 count-=(Bits)simd_inc; src+=simd_inc; cache+=simd_inc;
00167             }
00168 #undef MY_SIZEOF_INT_P
00169         }
00170         else
00171 #endif
00172         {
00173             while (count) {
00174                 if (GCC_UNLIKELY(src[0] != cache[0]))
00175                     goto cacheMiss;
00176                 count--; src++; cache++;
00177             }
00178         }
00179     }
00180 /* cacheHit */
00181     return true;
00182 cacheMiss:
00183     return false;
00184 }
00185 
00186 #if defined(C_SCALER_FULL_LINE)
00187 static unsigned int RENDER_scaler_countdown = 0;
00188 static const unsigned int RENDER_scaler_countdown_init = 12;
00189 
00190 static INLINE void cn_ScalerAddLines( Bitu changed, Bitu count ) {
00191     if ((Scaler_ChangedLineIndex & 1) == changed ) {
00192         Scaler_ChangedLines[Scaler_ChangedLineIndex] += count;
00193     } else {
00194         Scaler_ChangedLines[++Scaler_ChangedLineIndex] = count;
00195     }
00196     render.scale.outWrite += render.scale.outPitch * count;
00197 }
00198 
00199 static void RENDER_DrawLine_countdown(const void * s);
00200 
00201 static void RENDER_DrawLine_countdown_wait(const void * s) {
00202     if (RENDER_DrawLine_scanline_cacheHit(s)) { // line has not changed
00203         render.scale.inLine++;
00204         render.scale.cacheRead += render.scale.cachePitch;
00205         cn_ScalerAddLines(0,Scaler_Aspect[ render.scale.outLine++ ]);
00206     }
00207     else {
00208         RENDER_scaler_countdown = RENDER_scaler_countdown_init;
00209         RENDER_DrawLine = RENDER_DrawLine_countdown;
00210         RENDER_DrawLine( s );
00211     }
00212 }
00213 
00214 static void RENDER_DrawLine_countdown(const void * s) {
00215     render.scale.lineHandler(s);
00216     if (--RENDER_scaler_countdown == 0)
00217         RENDER_DrawLine = RENDER_DrawLine_countdown_wait;
00218 }
00219 #endif
00220 
00221 static void RENDER_StartLineHandler(const void * s) {
00222     if (RENDER_DrawLine_scanline_cacheHit(s)) { // line has not changed
00223         render.scale.cacheRead += render.scale.cachePitch;
00224         Scaler_ChangedLines[0] += Scaler_Aspect[ render.scale.inLine ];
00225         render.scale.inLine++;
00226         render.scale.outLine++;
00227     }
00228     else {
00229         if (!GFX_StartUpdate( render.scale.outWrite, render.scale.outPitch )) {
00230             RENDER_DrawLine = RENDER_EmptyLineHandler;
00231             return;
00232         }
00233         render.scale.outWrite += render.scale.outPitch * Scaler_ChangedLines[0];
00234 #if defined(C_SCALER_FULL_LINE)
00235         RENDER_scaler_countdown = RENDER_scaler_countdown_init;
00236         RENDER_DrawLine = RENDER_DrawLine_countdown;
00237 #else
00238         RENDER_DrawLine = render.scale.lineHandler;
00239 #endif
00240         RENDER_DrawLine( s );
00241     }
00242 }
00243 
00244 static void RENDER_FinishLineHandler(const void * s) {
00245     if (s) {
00246         const Bitu *src = (Bitu*)s;
00247         Bitu *cache = (Bitu*)(render.scale.cacheRead);
00248         for (Bitu x=render.src.start;x>0;) {
00249             cache[0] = src[0];
00250             x--; src++; cache++;
00251         }
00252     }
00253     render.scale.cacheRead += render.scale.cachePitch;
00254 }
00255 
00256 
00257 static void RENDER_ClearCacheHandler(const void * src) {
00258     Bitu x, width;
00259     Bit32u *srcLine, *cacheLine;
00260     srcLine = (Bit32u *)src;
00261     cacheLine = (Bit32u *)render.scale.cacheRead;
00262     width = render.scale.cachePitch / 4;
00263     for (x=0;x<width;x++)
00264         cacheLine[x] = ~srcLine[x];
00265     render.scale.lineHandler( src );
00266 }
00267 
00268 extern void GFX_SetTitle(Bit32s cycles,Bits frameskip,Bits timing,bool paused);
00269 
00270 bool RENDER_StartUpdate(void) {
00271     if (GCC_UNLIKELY(render.updating))
00272         return false;
00273     if (GCC_UNLIKELY(!render.active))
00274         return false;
00275     if (GCC_UNLIKELY(render.frameskip.count<render.frameskip.max)) {
00276         render.frameskip.count++;
00277         return false;
00278     }
00279     render.frameskip.count=0;
00280     if (render.scale.inMode == scalerMode8) {
00281         Check_Palette();
00282     }
00283     render.scale.inLine = 0;
00284     render.scale.outLine = 0;
00285     render.scale.cacheRead = (Bit8u*)&scalerSourceCache;
00286     render.scale.outWrite = 0;
00287     render.scale.outPitch = 0;
00288     Scaler_ChangedLines[0] = 0;
00289     Scaler_ChangedLineIndex = 0;
00290     /* Clearing the cache will first process the line to make sure it's never the same */
00291     if (GCC_UNLIKELY( render.scale.clearCache) ) {
00292 //      LOG_MSG("Clearing cache");
00293         //Will always have to update the screen with this one anyway, so let's update already
00294         if (GCC_UNLIKELY(!GFX_StartUpdate( render.scale.outWrite, render.scale.outPitch )))
00295             return false;
00296         render.fullFrame = true;
00297         RENDER_DrawLine = RENDER_ClearCacheHandler;
00298     } else {
00299         if (render.pal.changed) {
00300             /* Assume pal changes always do a full screen update anyway */
00301             if (GCC_UNLIKELY(!GFX_StartUpdate( render.scale.outWrite, render.scale.outPitch )))
00302                 return false;
00303             RENDER_DrawLine = render.scale.linePalHandler;
00304             render.fullFrame = true;
00305         } else {
00306             RENDER_DrawLine = RENDER_StartLineHandler;
00307             if (GCC_UNLIKELY(CaptureState & (CAPTURE_IMAGE|CAPTURE_VIDEO))) 
00308                 render.fullFrame = true;
00309             else
00310                 render.fullFrame = false;
00311         }
00312     }
00313     render.updating = true;
00314     return true;
00315 }
00316 
00317 static void RENDER_Halt( void ) {
00318     RENDER_DrawLine = RENDER_EmptyLineHandler;
00319     GFX_EndUpdate( 0 );
00320     render.updating=false;
00321     render.active=false;
00322 }
00323 
00324 extern Bitu PIC_Ticks;
00325 extern bool pause_on_vsync;
00326 void PauseDOSBox(bool pressed);
00327 void AspectRatio_mapper_shortcut(bool pressed);
00328 
00329 void RENDER_EndUpdate( bool abort ) {
00330     if (GCC_UNLIKELY(!render.updating))
00331         return;
00332 
00333     if (!abort && render.active && RENDER_DrawLine == RENDER_ClearCacheHandler)
00334         render.scale.clearCache = false;
00335 
00336     RENDER_DrawLine = RENDER_EmptyLineHandler;
00337     if (GCC_UNLIKELY(CaptureState & (CAPTURE_IMAGE|CAPTURE_VIDEO))) {
00338         Bitu pitch, flags;
00339         flags = 0;
00340         if (render.src.dblw != render.src.dblh) {
00341             if (render.src.dblw) flags|=CAPTURE_FLAG_DBLW;
00342             if (render.src.dblh) flags|=CAPTURE_FLAG_DBLH;
00343         }
00344         float fps = render.src.fps;
00345         pitch = render.scale.cachePitch;
00346         if (render.frameskip.max)
00347             fps /= 1+render.frameskip.max;
00348 
00349         if (Scaler_ChangedLineIndex == 0)
00350             flags |= CAPTURE_FLAG_NOCHANGE;
00351 
00352         CAPTURE_AddImage( render.src.width, render.src.height, render.src.bpp, pitch,
00353             flags, fps, (Bit8u *)&scalerSourceCache, (Bit8u*)&render.pal.rgb );
00354     }
00355     if ( render.scale.outWrite ) {
00356         GFX_EndUpdate( abort? NULL : Scaler_ChangedLines );
00357         render.frameskip.hadSkip[render.frameskip.index] = 0;
00358     } else {
00359 #if 0
00360         Bitu total = 0, i;
00361         render.frameskip.hadSkip[render.frameskip.index] = 1;
00362         for (i = 0;i<RENDER_SKIP_CACHE;i++) 
00363             total += render.frameskip.hadSkip[i];
00364         LOG_MSG( "Skipped frame %d %d", PIC_Ticks, (total * 100) / RENDER_SKIP_CACHE );
00365 #endif
00366         // Force output to update the screen even if nothing changed...
00367         // works only with Direct3D output (GFX_StartUpdate() was probably not even called)
00368         if (render.forceUpdate) GFX_EndUpdate( 0 );
00369     }
00370     render.frameskip.index = (render.frameskip.index + 1) & (RENDER_SKIP_CACHE - 1);
00371     render.updating=false;
00372 
00373     if (pause_on_vsync) {
00374         pause_on_vsync = false;
00375         PauseDOSBox(true);
00376     }
00377 }
00378 
00379 static Bitu MakeAspectTable(Bitu skip,Bitu height,double scaley,Bitu miny) {
00380     Bitu i;
00381     double lines=0;
00382     Bitu linesadded=0;
00383     for (i=0;i<skip;i++)
00384         Scaler_Aspect[i] = 0;
00385 
00386     height += skip;
00387     for (i=skip;i<height;i++) {
00388         lines += scaley;
00389         if (lines >= miny) {
00390             Bitu templines = (Bitu)lines;
00391             lines -= templines;
00392             linesadded += templines;
00393             Scaler_Aspect[i] = (Bit8u)templines;
00394         } else {
00395             Scaler_Aspect[i] = 0;
00396         }
00397     }
00398     return linesadded;
00399 }
00400 
00401 void RENDER_Reset( void ) {
00402     Bitu width=render.src.width;
00403     Bitu height=render.src.height;
00404     bool dblw=render.src.dblw;
00405     bool dblh=render.src.dblh;
00406 
00407     double gfx_scalew;
00408     double gfx_scaleh;
00409 
00410     if (width == 0 || height == 0)
00411         return;
00412     
00413     Bitu gfx_flags, xscale, yscale;
00414     ScalerSimpleBlock_t     *simpleBlock = &ScaleNormal1x;
00415     ScalerComplexBlock_t    *complexBlock = 0;
00416     gfx_scalew = 1;
00417     gfx_scaleh = 1;
00418 
00419 #if !C_XBRZ
00420     if (render.aspect == ASPECT_TRUE && !render.aspectOffload)
00421 #else
00422     if (render.aspect == ASPECT_TRUE && !render.aspectOffload && !(sdl_xbrz.enable && sdl_xbrz.scale_on))
00423 #endif
00424     {
00425         if (render.src.ratio>1.0) {
00426             gfx_scalew = 1;
00427             gfx_scaleh = render.src.ratio;
00428         } else {
00429             gfx_scalew = (1.0/render.src.ratio);
00430             gfx_scaleh = 1;
00431         }
00432     }
00433 
00434     if ((dblh && dblw) || (render.scale.forced && dblh == dblw/*this branch works best with equal scaling in both directions*/)) {
00435         /* Initialize always working defaults */
00436         if (render.scale.size == 2)
00437             simpleBlock = &ScaleNormal2x;
00438         else if (render.scale.size == 3)
00439             simpleBlock = &ScaleNormal3x;
00440         else if (render.scale.size == 1 && !(dblh || dblw) && render.scale.hardware)
00441             simpleBlock = &ScaleNormal1x;
00442         else if (render.scale.size == 4 && !(dblh || dblw) && render.scale.hardware)
00443             simpleBlock = &ScaleNormal2x;
00444         else if (render.scale.size == 6 && !(dblh || dblw) && render.scale.hardware)
00445             simpleBlock = &ScaleNormal3x;
00446         else if (render.scale.size == 4 && !render.scale.hardware)
00447             simpleBlock = &ScaleNormal4x;
00448         else if (render.scale.size == 5 && !render.scale.hardware)
00449             simpleBlock = &ScaleNormal5x;
00450         else if (render.scale.size == 8 && !(dblh || dblw) && render.scale.hardware)
00451             simpleBlock = &ScaleNormal4x;
00452         else if (render.scale.size == 10 && !(dblh || dblw) && render.scale.hardware)
00453             simpleBlock = &ScaleNormal5x;
00454         /* Maybe override them */
00455 #if RENDER_USE_ADVANCED_SCALERS>0
00456         switch (render.scale.op) {
00457 #if RENDER_USE_ADVANCED_SCALERS>2
00458         case scalerOpAdvInterp:
00459             if (render.scale.size == 2)
00460                 complexBlock = &ScaleAdvInterp2x;
00461             else if (render.scale.size == 3)
00462                 complexBlock = &ScaleAdvInterp3x;
00463             break;
00464         case scalerOpAdvMame:
00465             if (render.scale.size == 2)
00466                 complexBlock = &ScaleAdvMame2x;
00467             else if (render.scale.size == 3)
00468                 complexBlock = &ScaleAdvMame3x;
00469             break;
00470         case scalerOpHQ:
00471             if (render.scale.size == 2)
00472                 complexBlock = &ScaleHQ2x;
00473             else if (render.scale.size == 3)
00474                 complexBlock = &ScaleHQ3x;
00475             break;
00476         case scalerOpSuperSaI:
00477             if (render.scale.size == 2)
00478                 complexBlock = &ScaleSuper2xSaI;
00479             break;
00480         case scalerOpSuperEagle:
00481             if (render.scale.size == 2)
00482                 complexBlock = &ScaleSuperEagle;
00483             break;
00484         case scalerOpSaI:
00485             if (render.scale.size == 2)
00486                 complexBlock = &Scale2xSaI;
00487             break;
00488 #endif
00489         case scalerOpTV:
00490             if (render.scale.size == 2)
00491                 simpleBlock = &ScaleTV2x;
00492             else if (render.scale.size == 3)
00493                 simpleBlock = &ScaleTV3x;
00494             break;
00495         case scalerOpRGB:
00496             if (render.scale.size == 2)
00497                 simpleBlock = &ScaleRGB2x;
00498             else if (render.scale.size == 3)
00499                 simpleBlock = &ScaleRGB3x;
00500             break;
00501         case scalerOpScan:
00502             if (render.scale.size == 2)
00503                 simpleBlock = &ScaleScan2x;
00504             else if (render.scale.size == 3)
00505                 simpleBlock = &ScaleScan3x;
00506             break;
00507         case scalerOpGray:
00508             if (render.scale.size == 1){
00509                                 simpleBlock = &ScaleGrayNormal;
00510             }else if (render.scale.size == 2){
00511                                 simpleBlock = &ScaleGray2x;
00512             }
00513         break;
00514         default:
00515             break;
00516         }
00517 #endif
00518     } else if (dblw && !render.scale.hardware) {
00519       if(scalerOpGray == render.scale.op){
00520         simpleBlock = &ScaleGrayDw;
00521       }else{
00522           if (render.scale.forced && render.scale.size >= 2)
00523               simpleBlock = &ScaleNormal2xDw;
00524           else
00525               simpleBlock = &ScaleNormalDw;
00526       }
00527     } else if (dblh && !render.scale.hardware) {
00528                 //Check whether tv2x and scan2x is selected
00529                 if(scalerOpGray == render.scale.op){
00530                         simpleBlock = &ScaleGrayDh;
00531     }else if(scalerOpTV == render.scale.op){
00532                         simpleBlock = &ScaleTVDh;
00533         }else if(scalerOpScan == render.scale.op){
00534                         simpleBlock = &ScaleScanDh;
00535         }else{
00536             if (render.scale.forced && render.scale.size >= 2)
00537                 simpleBlock = &ScaleNormal2xDh;
00538             else
00539                 simpleBlock = &ScaleNormalDh;
00540         }
00541     } else  {
00542 forcenormal:
00543         complexBlock = 0;
00544         if(scalerOpGray==render.scale.op){
00545           simpleBlock = &ScaleGrayNormal;
00546         }else{
00547           simpleBlock = &ScaleNormal1x;
00548         }
00549     }
00550     if (complexBlock) {
00551 #if RENDER_USE_ADVANCED_SCALERS>1
00552         if ((width >= SCALER_COMPLEXWIDTH - 16) || height >= SCALER_COMPLEXHEIGHT - 16) {
00553             LOG_MSG("Scaler can't handle this resolution, going back to normal");
00554             goto forcenormal;
00555         }
00556 #else
00557         goto forcenormal;
00558 #endif
00559         gfx_flags = complexBlock->gfxFlags;
00560         xscale = complexBlock->xscale;  
00561         yscale = complexBlock->yscale;
00562 //      LOG_MSG("Scaler:%s",complexBlock->name);
00563     } else {
00564         gfx_flags = simpleBlock->gfxFlags;
00565         xscale = simpleBlock->xscale;   
00566         yscale = simpleBlock->yscale;
00567 //      LOG_MSG("Scaler:%s",simpleBlock->name);
00568     }
00569     switch (render.src.bpp) {
00570     case 8:
00571         render.src.start = ( render.src.width * 1) / sizeof(Bitu);
00572         if (gfx_flags & GFX_CAN_8)
00573             gfx_flags |= GFX_LOVE_8;
00574         else
00575             gfx_flags |= GFX_LOVE_32;
00576         break;
00577     case 15:
00578         render.src.start = ( render.src.width * 2) / sizeof(Bitu);
00579         gfx_flags |= GFX_LOVE_15;
00580         gfx_flags = (gfx_flags & ~GFX_CAN_8) | GFX_RGBONLY;
00581         break;
00582     case 16:
00583         render.src.start = ( render.src.width * 2) / sizeof(Bitu);
00584         gfx_flags |= GFX_LOVE_16;
00585         gfx_flags = (gfx_flags & ~GFX_CAN_8) | GFX_RGBONLY;
00586         break;
00587     case 32:
00588         render.src.start = ( render.src.width * 4) / sizeof(Bitu);
00589         gfx_flags |= GFX_LOVE_32;
00590         gfx_flags = (gfx_flags & ~GFX_CAN_8) | GFX_RGBONLY;
00591         break;
00592     default:
00593         render.src.start = ( render.src.width * 1) / sizeof(Bitu);
00594         if (gfx_flags & GFX_CAN_8)
00595             gfx_flags |= GFX_LOVE_8;
00596         else
00597             gfx_flags |= GFX_LOVE_32;
00598         break;
00599     }
00600 #if !defined(C_SDL2)
00601     gfx_flags=GFX_GetBestMode(gfx_flags);
00602 #else
00603     gfx_flags &= ~GFX_SCALING;
00604     gfx_flags |= GFX_RGBONLY | GFX_CAN_RANDOM;
00605 #endif
00606     if (!gfx_flags) {
00607         if (!complexBlock && simpleBlock == &ScaleNormal1x) 
00608             E_Exit("Failed to create a rendering output");
00609         else 
00610             goto forcenormal;
00611     }
00612     width *= xscale;
00613     Bitu skip = complexBlock ? 1 : 0;
00614     if (gfx_flags & GFX_SCALING) {
00615         if(render.scale.size == 1 && render.scale.hardware) { //hardware_none
00616             if(dblh)
00617             gfx_scaleh *= 1;
00618             if(dblw)
00619             gfx_scalew *= 1;
00620         } else if(render.scale.size == 4 && render.scale.hardware) {
00621             if(dblh)
00622             gfx_scaleh *= 2;
00623             if(dblw)
00624             gfx_scalew *= 2;
00625         } else if(render.scale.size == 6 && render.scale.hardware) {
00626             if(dblh && dblw) {
00627             gfx_scaleh *= 3; gfx_scalew *= 3;
00628             } else if(dblh) {
00629             gfx_scaleh *= 2;
00630             } else if(dblw)
00631             gfx_scalew *= 2;
00632         } else if(render.scale.size == 8 && render.scale.hardware) { //hardware4x
00633             if(dblh)
00634             gfx_scaleh *= 4;
00635             if(dblw)
00636             gfx_scalew *= 4;
00637         } else if(render.scale.size == 10 && render.scale.hardware) { //hardware5x
00638             if(dblh && dblw) {
00639             gfx_scaleh *= 5; gfx_scalew *= 5;
00640             } else if(dblh) {
00641             gfx_scaleh *= 4;
00642             } else if(dblw)
00643             gfx_scalew *= 4;
00644         }
00645         height = MakeAspectTable(skip, render.src.height, (double)yscale, yscale );
00646     } else {
00647         // Print a warning when hardware scalers are selected, hopefully the first
00648         // video mode will not have dblh or dblw or AR will be wrong
00649         if (render.scale.hardware) {
00650             LOG_MSG("Output does not support hardware scaling, switching to normal scalers");
00651             render.scale.hardware=false;
00652         }
00653         if ((gfx_flags & GFX_CAN_RANDOM) && gfx_scaleh > 1) {
00654             gfx_scaleh *= yscale;
00655             height = MakeAspectTable( skip, render.src.height, gfx_scaleh, yscale );
00656         } else {
00657             gfx_flags &= ~GFX_CAN_RANDOM;       //Hardware surface when possible
00658             height = MakeAspectTable( skip, render.src.height, (double)yscale, yscale);
00659         }
00660     }
00661 /* update the aspect ratio */
00662     sdl.srcAspect.x = (int)(render.src.width * (render.src.dblw ? 2 : 1));
00663     sdl.srcAspect.y = (int)floor((render.src.height * (render.src.dblh ? 2 : 1) * render.src.ratio) + 0.5);
00664     sdl.srcAspect.xToY = (double)sdl.srcAspect.x / sdl.srcAspect.y;
00665     sdl.srcAspect.yToX = (double)sdl.srcAspect.y / sdl.srcAspect.x;
00666     LOG_MSG("Aspect ratio: %u x %u  xToY=%.3f yToX=%.3f",sdl.srcAspect.x,sdl.srcAspect.y,sdl.srcAspect.xToY,sdl.srcAspect.yToX);
00667 /* Setup the scaler variables */
00668     gfx_flags=GFX_SetSize(width,height,gfx_flags,gfx_scalew,gfx_scaleh,&RENDER_CallBack);
00669     if (gfx_flags & GFX_CAN_8)
00670         render.scale.outMode = scalerMode8;
00671     else if (gfx_flags & GFX_CAN_15)
00672         render.scale.outMode = scalerMode15;
00673     else if (gfx_flags & GFX_CAN_16)
00674         render.scale.outMode = scalerMode16;
00675     else if (gfx_flags & GFX_CAN_32)
00676         render.scale.outMode = scalerMode32;
00677     else 
00678         E_Exit("Failed to create a rendering output");
00679     ScalerLineBlock_t *lineBlock;
00680     if (gfx_flags & GFX_HARDWARE) {
00681 #if RENDER_USE_ADVANCED_SCALERS>1
00682         if (complexBlock) {
00683             lineBlock = &ScalerCache;
00684             render.scale.complexHandler = complexBlock->Linear[ render.scale.outMode ];
00685         } else
00686 #endif
00687         {
00688             render.scale.complexHandler = 0;
00689             lineBlock = &simpleBlock->Linear;
00690         }
00691     } else {
00692 #if RENDER_USE_ADVANCED_SCALERS>1
00693         if (complexBlock) {
00694             lineBlock = &ScalerCache;
00695             render.scale.complexHandler = complexBlock->Random[ render.scale.outMode ];
00696         } else
00697 #endif
00698         {
00699             render.scale.complexHandler = 0;
00700             lineBlock = &simpleBlock->Random;
00701         }
00702     }
00703     switch (render.src.bpp) {
00704     case 8:
00705         render.scale.lineHandler = (*lineBlock)[0][render.scale.outMode];
00706         render.scale.linePalHandler = (*lineBlock)[4][render.scale.outMode];
00707         render.scale.inMode = scalerMode8;
00708         render.scale.cachePitch = render.src.width * 1;
00709         break;
00710     case 15:
00711         render.scale.lineHandler = (*lineBlock)[1][render.scale.outMode];
00712         render.scale.linePalHandler = 0;
00713         render.scale.inMode = scalerMode15;
00714         render.scale.cachePitch = render.src.width * 2;
00715         break;
00716     case 16:
00717         render.scale.lineHandler = (*lineBlock)[2][render.scale.outMode];
00718         render.scale.linePalHandler = 0;
00719         render.scale.inMode = scalerMode16;
00720         render.scale.cachePitch = render.src.width * 2;
00721         break;
00722     case 32:
00723         render.scale.lineHandler = (*lineBlock)[3][render.scale.outMode];
00724         render.scale.linePalHandler = 0;
00725         render.scale.inMode = scalerMode32;
00726         render.scale.cachePitch = render.src.width * 4;
00727         break;
00728     default:
00729         //render.src.bpp=8;
00730         render.scale.lineHandler = (*lineBlock)[0][render.scale.outMode];
00731         render.scale.linePalHandler = (*lineBlock)[4][render.scale.outMode];
00732         render.scale.inMode = scalerMode8;
00733         render.scale.cachePitch = render.src.width * 1;
00734         break;
00735         //E_Exit("RENDER:Wrong source bpp %d", render.src.bpp );
00736     }
00737     render.scale.blocks = render.src.width / SCALER_BLOCKSIZE;
00738     render.scale.lastBlock = render.src.width % SCALER_BLOCKSIZE;
00739     render.scale.inHeight = render.src.height;
00740     /* Reset the palette change detection to it's initial value */
00741     render.pal.first= 0;
00742     render.pal.last = 255;
00743     render.pal.changed = false;
00744     memset(render.pal.modified, 0, sizeof(render.pal.modified));
00745     //Finish this frame using a copy only handler
00746     RENDER_DrawLine = RENDER_FinishLineHandler;
00747     render.scale.outWrite = 0;
00748     /* Signal the next frame to first reinit the cache */
00749     render.scale.clearCache = true;
00750     render.active=true;
00751 
00752     last_gfx_flags = gfx_flags;
00753 }
00754 
00755 void RENDER_CallBack( GFX_CallBackFunctions_t function ) {
00756     if (function == GFX_CallBackStop) {
00757         RENDER_Halt( ); 
00758         return;
00759     } else if (function == GFX_CallBackRedraw) {
00760         render.scale.clearCache = true;
00761         return;
00762     } else if ( function == GFX_CallBackReset) {
00763         GFX_EndUpdate( 0 ); 
00764         RENDER_Reset();
00765     } else {
00766         E_Exit("Unhandled GFX_CallBackReset %d", function );
00767     }
00768 }
00769 
00770 void RENDER_SetSize(Bitu width,Bitu height,Bitu bpp,float fps,double scrn_ratio) {
00771     RENDER_Halt( );
00772     if (!width || !height || width > SCALER_MAXWIDTH || height > SCALER_MAXHEIGHT) {
00773         LOG(LOG_MISC,LOG_WARN)("RENDER_SetSize() rejected video mode %u x %u",(unsigned int)width,(unsigned int)height);
00774         return; 
00775     }
00776 
00777     // figure out doublewidth/height values
00778     bool dblw = false;
00779     bool dblh = false;
00780     double ratio = (((double)width)/((double)height))/scrn_ratio;
00781     if(ratio > 1.6) {
00782         dblh=true;
00783         ratio /= 2.0;
00784     } else if(ratio < 0.75) {
00785         dblw=true;
00786         ratio *= 2.0;
00787     } else if(width < 370 && height < 280) {
00788         dblw=true; dblh=true;
00789     }
00790     LOG_MSG("pixratio %1.3f, dw %s, dh %s",ratio,dblw?"true":"false",dblh?"true":"false");
00791 
00792     if ( ratio > 1.0 ) {
00793         double target = height * ratio + 0.025;
00794         ratio = target / height;
00795     } else {
00796         //This would alter the width of the screen, we don't care about rounding errors here
00797     }
00798     render.src.width=width;
00799     render.src.height=height;
00800     render.src.bpp=bpp;
00801     render.src.dblw=dblw;
00802     render.src.dblh=dblh;
00803     render.src.fps=fps;
00804     render.src.ratio=ratio;
00805     render.src.scrn_ratio=scrn_ratio;
00806     RENDER_Reset( );
00807 }
00808 
00809 void BlankDisplay(void);
00810 static void BlankTestRefresh(bool pressed) {
00811     (void)pressed;
00812     BlankDisplay();
00813 }
00814 
00815 //extern void GFX_SetTitle(Bit32s cycles, Bits frameskip, Bits timing, bool paused);
00816 static void IncreaseFrameSkip(bool pressed) {
00817     if (!pressed)
00818         return;
00819     if (render.frameskip.max<10) render.frameskip.max++;
00820     LOG_MSG("Frame Skip at %d",(int)render.frameskip.max);
00821     GFX_SetTitle(-1,(Bits)render.frameskip.max,-1,false);
00822 }
00823 
00824 static void DecreaseFrameSkip(bool pressed) {
00825     if (!pressed)
00826         return;
00827     if (render.frameskip.max>0) render.frameskip.max--;
00828     LOG_MSG("Frame Skip at %d",(int)render.frameskip.max);
00829     GFX_SetTitle(-1,(Bits)render.frameskip.max,-1,false);
00830 }
00831 /* Disabled as I don't want to waste a keybind for that. Might be used in the future (Qbix)
00832 static void ChangeScaler(bool pressed) {
00833     if (!pressed)
00834         return;
00835     render.scale.op = (scalerOperation)((int)render.scale.op+1);
00836     if((render.scale.op) >= scalerLast || render.scale.size == 1) {
00837         render.scale.op = (scalerOperation)0;
00838         if(++render.scale.size > 3)
00839             render.scale.size = 1;
00840     }
00841     RENDER_CallBack( GFX_CallBackReset );
00842 } */
00843 
00844 #include "vga.h"
00845 
00846 void RENDER_UpdateFromScalerSetting(void);
00847 
00848 void RENDER_SetForceUpdate(bool f) {
00849     render.forceUpdate = f;
00850 }
00851 
00852 void RENDER_UpdateFrameskipMenu(void) {
00853     char tmp[64];
00854 
00855     for (unsigned int f=0;f <= 10;f++) {
00856         sprintf(tmp,"frameskip_%u",f);
00857         DOSBoxMenu::item &item = mainMenu.get_item(tmp);
00858         item.check(render.frameskip.max == f);
00859     }
00860 }
00861 
00862 void VGA_SetupDrawing(Bitu /*val*/);
00863 void RENDER_UpdateScalerMenu(void);
00864 
00865 void RENDER_OnSectionPropChange(Section *x) {
00866     (void)x;//UNUSED
00867     Section_prop * section = static_cast<Section_prop *>(control->GetSection("render"));
00868 
00869     bool p_doublescan = vga.draw.doublescan_set;
00870     bool p_char9 = vga.draw.char9_set;
00871     int p_aspect = render.aspect;
00872 
00873     std::string s_aspect = section->Get_string("aspect");
00874     render.aspect = ASPECT_FALSE;
00875     if (s_aspect == "true" || s_aspect == "1" || s_aspect == "yes") render.aspect = ASPECT_TRUE;
00876 #if C_SURFACE_POSTRENDER_ASPECT
00877     if (s_aspect == "nearest") render.aspect = ASPECT_NEAREST;
00878     if (s_aspect == "bilinear") render.aspect = ASPECT_BILINEAR;
00879 #endif
00880 
00881     render.frameskip.max = (Bitu)section->Get_int("frameskip");
00882 
00883     vga.draw.doublescan_set=section->Get_bool("doublescan");
00884     vga.draw.char9_set=section->Get_bool("char9");
00885 
00886     if (render.aspect != p_aspect || vga.draw.doublescan_set != p_doublescan || vga.draw.char9_set != p_char9)
00887         RENDER_CallBack(GFX_CallBackReset);
00888     if (vga.draw.doublescan_set != p_doublescan || vga.draw.char9_set != p_char9)
00889         VGA_StartResize();
00890 
00891     mainMenu.get_item("vga_9widetext").check(vga.draw.char9_set).refresh_item(mainMenu);
00892     mainMenu.get_item("doublescan").check(vga.draw.doublescan_set).refresh_item(mainMenu);
00893     mainMenu.get_item("mapper_aspratio").check(render.aspect).refresh_item(mainMenu);
00894 
00895 #if C_XBRZ
00896     xBRZ_Change_Options(section);
00897 #endif
00898 
00899     RENDER_UpdateFrameskipMenu();
00900     RENDER_UpdateFromScalerSetting();
00901     RENDER_UpdateScalerMenu();
00902 }
00903 
00904 std::string RENDER_GetScaler(void) {
00905     Section_prop * section=static_cast<Section_prop *>(control->GetSection("render"));
00906     Prop_multival* prop = section->Get_multival("scaler");
00907     return prop->GetSection()->Get_string("type");
00908 }
00909 
00910 extern const char *scaler_menu_opts[][2];
00911 
00912 void RENDER_UpdateScalerMenu(void) {
00913     const std::string scaler = RENDER_GetScaler();
00914 
00915     mainMenu.get_item("scaler_forced").check(render.scale.forced).refresh_item(mainMenu);
00916     for (size_t i=0;scaler_menu_opts[i][0] != NULL;i++) {
00917         const std::string name = std::string("scaler_set_") + scaler_menu_opts[i][0];
00918         mainMenu.get_item(name).check(scaler == scaler_menu_opts[i][0]).refresh_item(mainMenu);
00919     }
00920 }
00921 
00922 void RENDER_UpdateFromScalerSetting(void) {
00923     Section_prop * section=static_cast<Section_prop *>(control->GetSection("render"));
00924     Prop_multival* prop = section->Get_multival("scaler");
00925     std::string f = prop->GetSection()->Get_string("force");
00926     std::string scaler = prop->GetSection()->Get_string("type");
00927 
00928 #if C_XBRZ
00929     bool old_xBRZ_enable = sdl_xbrz.enable;
00930     sdl_xbrz.enable = false;
00931 #endif
00932 
00933     bool p_forced = render.scale.forced;
00934     unsigned int p_size = (unsigned int)(render.scale.size);
00935     bool p_hardware = render.scale.hardware;
00936     unsigned int p_op = render.scale.op;
00937 
00938     render.scale.forced = false;
00939     if(f == "forced") render.scale.forced = true;
00940    
00941     if (scaler == "none") { render.scale.op = scalerOpNormal; render.scale.size = 1; render.scale.hardware=false; }
00942     else if (scaler == "normal2x") { render.scale.op = scalerOpNormal; render.scale.size = 2; render.scale.hardware=false; }
00943     else if (scaler == "normal3x") { render.scale.op = scalerOpNormal; render.scale.size = 3; render.scale.hardware=false; }
00944     else if (scaler == "normal4x") { render.scale.op = scalerOpNormal; render.scale.size = 4; render.scale.hardware=false; }
00945     else if (scaler == "normal5x") { render.scale.op = scalerOpNormal; render.scale.size = 5; render.scale.hardware=false; }
00946 #if RENDER_USE_ADVANCED_SCALERS>2
00947     else if (scaler == "advmame2x") { render.scale.op = scalerOpAdvMame; render.scale.size = 2; render.scale.hardware=false; }
00948     else if (scaler == "advmame3x") { render.scale.op = scalerOpAdvMame; render.scale.size = 3; render.scale.hardware=false; }
00949     else if (scaler == "advinterp2x") { render.scale.op = scalerOpAdvInterp; render.scale.size = 2; render.scale.hardware=false; }
00950     else if (scaler == "advinterp3x") { render.scale.op = scalerOpAdvInterp; render.scale.size = 3; render.scale.hardware=false; }
00951     else if (scaler == "hq2x") { render.scale.op = scalerOpHQ; render.scale.size = 2; render.scale.hardware=false; }
00952     else if (scaler == "hq3x") { render.scale.op = scalerOpHQ; render.scale.size = 3; render.scale.hardware=false; }
00953     else if (scaler == "2xsai") { render.scale.op = scalerOpSaI; render.scale.size = 2; render.scale.hardware=false; }
00954     else if (scaler == "super2xsai") { render.scale.op = scalerOpSuperSaI; render.scale.size = 2; render.scale.hardware=false; }
00955     else if (scaler == "supereagle") { render.scale.op = scalerOpSuperEagle; render.scale.size = 2; render.scale.hardware=false; }
00956 #endif
00957 #if RENDER_USE_ADVANCED_SCALERS>0
00958     else if (scaler == "tv2x") { render.scale.op = scalerOpTV; render.scale.size = 2; render.scale.hardware=false; }
00959     else if (scaler == "tv3x") { render.scale.op = scalerOpTV; render.scale.size = 3; render.scale.hardware=false; }
00960     else if (scaler == "rgb2x"){ render.scale.op = scalerOpRGB; render.scale.size = 2; render.scale.hardware=false; }
00961     else if (scaler == "rgb3x"){ render.scale.op = scalerOpRGB; render.scale.size = 3; render.scale.hardware=false; }
00962     else if (scaler == "scan2x"){ render.scale.op = scalerOpScan; render.scale.size = 2; render.scale.hardware=false; }
00963     else if (scaler == "scan3x"){ render.scale.op = scalerOpScan; render.scale.size = 3; render.scale.hardware=false; }
00964     else if (scaler == "gray"){ render.scale.op = scalerOpGray; render.scale.size = 1; render.scale.hardware=false; }
00965     else if (scaler == "gray2x"){ render.scale.op = scalerOpGray; render.scale.size = 2; render.scale.hardware=false; }
00966 #endif
00967     else if (scaler == "hardware_none") { render.scale.op = scalerOpNormal; render.scale.size = 1; render.scale.hardware=true; }
00968     else if (scaler == "hardware2x") { render.scale.op = scalerOpNormal; render.scale.size = 4; render.scale.hardware=true; }
00969     else if (scaler == "hardware3x") { render.scale.op = scalerOpNormal; render.scale.size = 6; render.scale.hardware=true; }
00970     else if (scaler == "hardware4x") { render.scale.op = scalerOpNormal; render.scale.size = 8; render.scale.hardware=true; }
00971     else if (scaler == "hardware5x") { render.scale.op = scalerOpNormal; render.scale.size = 10; render.scale.hardware=true; }
00972 #if C_XBRZ
00973     else if (scaler == "xbrz" || scaler == "xbrz_bilinear") { 
00974         render.scale.op = scalerOpNormal; 
00975         render.scale.size = 1; 
00976         render.scale.hardware = false; 
00977         vga.draw.doublescan_set = false; 
00978         sdl_xbrz.enable = true; 
00979         sdl_xbrz.postscale_bilinear = (scaler == "xbrz_bilinear");
00980     }
00981 #endif
00982 
00983     bool reset = false;
00984 
00985 #if C_XBRZ
00986     if (old_xBRZ_enable != sdl_xbrz.enable) reset = true;
00987 #endif
00988     if (p_forced != render.scale.forced) reset = true;
00989     if (p_size != render.scale.size) reset = true;
00990     if (p_hardware != render.scale.hardware) reset = true;
00991     if (p_op != render.scale.op) reset = true;
00992 
00993     if (reset) RENDER_CallBack(GFX_CallBackReset);
00994 }
00995 
00996 void RENDER_Init() {
00997     Section_prop * section=static_cast<Section_prop *>(control->GetSection("render"));
00998 
00999     LOG(LOG_MISC,LOG_DEBUG)("Initializing renderer");
01000 
01001     control->GetSection("render")->onpropchange.push_back(&RENDER_OnSectionPropChange);
01002 
01003     vga.draw.doublescan_set=section->Get_bool("doublescan");
01004     vga.draw.char9_set=section->Get_bool("char9");
01005 
01006         //Set monochrome mode color and brightness
01007         vga.draw.monochrome_pal=0;
01008         vga.draw.monochrome_bright=1;
01009   Prop_multival* prop = section->Get_multival("monochrome_pal");
01010   std::string s_bright = prop->GetSection()->Get_string("bright");
01011   std::string s_color = prop->GetSection()->Get_string("color");
01012   LOG_MSG("monopal: %s, %s", s_color.c_str(), s_bright.c_str());
01013         if("bright"==s_bright){
01014                 vga.draw.monochrome_bright=0;
01015         }
01016         if("green"==s_color){
01017                 vga.draw.monochrome_pal=0;
01018         }else if("amber"==s_color){
01019                 vga.draw.monochrome_pal=1;
01020         }else if("gray"==s_color){
01021                 vga.draw.monochrome_pal=2;
01022         }else if("white"==s_color){
01023                 vga.draw.monochrome_pal=3;
01024         }
01025 
01026     //For restarting the renderer.
01027     static bool running = false;
01028     int aspect = render.aspect;
01029     Bitu scalersize = render.scale.size;
01030     bool scalerforced = render.scale.forced;
01031     scalerOperation_t scaleOp = render.scale.op;
01032 
01033     render.scale.cacheRead = NULL;
01034     render.scale.outWrite = NULL;
01035 
01036     render.pal.first=0;
01037     render.pal.last=255;
01038 
01039     std::string s_aspect = section->Get_string("aspect");
01040     render.aspect = ASPECT_FALSE;
01041     if (s_aspect == "true" || s_aspect == "1") render.aspect = ASPECT_TRUE;
01042 #if C_SURFACE_POSTRENDER_ASPECT
01043     if (s_aspect == "nearest") render.aspect = ASPECT_NEAREST;
01044     if (s_aspect == "bilinear") render.aspect = ASPECT_BILINEAR;
01045 #endif
01046 
01047     render.frameskip.max=(Bitu)section->Get_int("frameskip");
01048 
01049     MAPPER_AddHandler(DecreaseFrameSkip,MK_nothing,0,"decfskip","Dec Fskip");
01050     MAPPER_AddHandler(IncreaseFrameSkip,MK_nothing,0,"incfskip","Inc Fskip");
01051 
01052         DOSBoxMenu::item *item;
01053 
01054         MAPPER_AddHandler(&AspectRatio_mapper_shortcut, MK_nothing, 0, "aspratio", "AspRatio", &item);
01055         item->set_text("Fit to aspect ratio");
01056 
01057     // DEBUG option
01058     MAPPER_AddHandler(BlankTestRefresh,MK_nothing,0,"blankrefreshtest","RefrshTest");
01059 
01060     mainMenu.get_item("vga_9widetext").check(vga.draw.char9_set).refresh_item(mainMenu);
01061     mainMenu.get_item("doublescan").check(vga.draw.doublescan_set).refresh_item(mainMenu);
01062     mainMenu.get_item("mapper_aspratio").check(render.aspect).refresh_item(mainMenu);
01063 
01064     RENDER_UpdateFrameskipMenu();
01065 
01066     /* BUG FIX: Some people's dosbox.conf files have frameskip=-1 WTF?? */
01067     /* without this fix, nothing displays, EVER */
01068     if ((int)render.frameskip.max < 0) render.frameskip.max = 0;
01069                                 
01070     render.frameskip.count=0;
01071     render.forceUpdate=false;
01072     std::string cline;
01073     std::string scaler;
01074     //Check for commandline paramters and parse them through the configclass so they get checked against allowed values
01075     if (control->cmdline->FindString("-scaler",cline,true)) {
01076         section->HandleInputline(std::string("scaler=") + cline);
01077     } else if (control->cmdline->FindString("-forcescaler",cline,true)) {
01078         section->HandleInputline(std::string("scaler=") + cline + " forced");
01079     }
01080 
01081     RENDER_UpdateFromScalerSetting();
01082 
01083     vga_alt_new_mode = control->opt_alt_vga_render || section->Get_bool("alt render");
01084     if (vga_alt_new_mode) LOG_MSG("Alternative VGA render engine not yet fully implemented!");
01085 
01086     render.autofit=section->Get_bool("autofit");
01087 
01088     //If something changed that needs a ReInit
01089     // Only ReInit when there is a src.bpp (fixes crashes on startup and directly changing the scaler without a screen specified yet)
01090     if(running && render.src.bpp && ((render.aspect != aspect) || (render.scale.op != scaleOp) || 
01091                   (render.scale.size != scalersize) || (render.scale.forced != scalerforced) ||
01092                    render.scale.forced))
01093         RENDER_CallBack( GFX_CallBackReset );
01094 
01095     if(!running) render.updating=true;
01096     running = true;
01097 
01098     GFX_SetTitle(-1,(Bits)render.frameskip.max,-1,false);
01099 
01100     RENDER_UpdateScalerMenu();
01101 }
01102 
01103 //save state support
01104 namespace
01105 {
01106 class SerializeRender : public SerializeGlobalPOD
01107 {
01108 public:
01109         SerializeRender() : SerializeGlobalPOD("Render")
01110         {}
01111 
01112 private:
01113         virtual void getBytes(std::ostream& stream)
01114         {
01115                 SerializeGlobalPOD::getBytes(stream);
01116 
01117 
01118                 // - pure data
01119                 WRITE_POD( &render.src, render.src );
01120 
01121                 WRITE_POD( &render.pal, render.pal );
01122                 WRITE_POD( &render.updating, render.updating );
01123                 WRITE_POD( &render.active, render.active );
01124                 WRITE_POD( &render.fullFrame, render.fullFrame );
01125                 WRITE_POD( &render.frameskip, render.frameskip );
01126         }
01127 
01128         virtual void setBytes(std::istream& stream)
01129         {
01130                 SerializeGlobalPOD::setBytes(stream);
01131 
01132 
01133                 // - pure data
01134                 READ_POD( &render.src, render.src );
01135 
01136                 READ_POD( &render.pal, render.pal );
01137                 READ_POD( &render.updating, render.updating );
01138                 READ_POD( &render.active, render.active );
01139                 READ_POD( &render.fullFrame, render.fullFrame );
01140                 READ_POD( &render.frameskip, render.frameskip );
01141 
01142                 //***************************************
01143                 //***************************************
01144 
01145                 // reset screen
01146                 //memset( &render.frameskip, 0, sizeof(render.frameskip) );
01147 
01148                 render.scale.clearCache = true;
01149                 if( render.scale.outWrite ) { GFX_EndUpdate(NULL); }
01150 
01151                 RENDER_SetSize( render.src.width, render.src.height, render.src.bpp, render.src.fps, render.src.ratio );
01152 
01153         }
01154 } dummy;
01155 }