DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator
src/gui/render.cpp
00001 /*
00002  *  Copyright (C) 2002-2015  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
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 
00034 #include "render_scalers.h"
00035 #if defined(__SSE__)
00036 #include <xmmintrin.h>
00037 #include <emmintrin.h>
00038 #endif
00039 
00040 Render_t render;
00041 Bitu last_gfx_flags = 0;
00042 ScalerLineHandler_t RENDER_DrawLine;
00043 
00044 void RENDER_CallBack( GFX_CallBackFunctions_t function );
00045 
00046 static void Check_Palette(void) {
00047     /* Clean up any previous changed palette data */
00048     if (render.pal.changed) {
00049         memset(render.pal.modified, 0, sizeof(render.pal.modified));
00050         render.pal.changed = false;
00051     }
00052     if (render.pal.first>render.pal.last) 
00053         return;
00054     Bitu i;
00055     switch (render.scale.outMode) {
00056     case scalerMode8:
00057         GFX_SetPalette(render.pal.first,render.pal.last-render.pal.first+1,(GFX_PalEntry *)&render.pal.rgb[render.pal.first]);
00058         break;
00059     case scalerMode15:
00060     case scalerMode16:
00061         for (i=render.pal.first;i<=render.pal.last;i++) {
00062             Bit8u r=render.pal.rgb[i].red;
00063             Bit8u g=render.pal.rgb[i].green;
00064             Bit8u b=render.pal.rgb[i].blue;
00065             Bit16u newPal = GFX_GetRGB(r,g,b);
00066             if (newPal != render.pal.lut.b16[i]) {
00067                 render.pal.changed = true;
00068                 render.pal.modified[i] = 1;
00069                 render.pal.lut.b16[i] = newPal;
00070             }
00071         }
00072         break;
00073     case scalerMode32:
00074     default:
00075         for (i=render.pal.first;i<=render.pal.last;i++) {
00076             Bit8u r=render.pal.rgb[i].red;
00077             Bit8u g=render.pal.rgb[i].green;
00078             Bit8u b=render.pal.rgb[i].blue;
00079             Bit32u newPal = GFX_GetRGB(r,g,b);
00080             if (newPal != render.pal.lut.b32[i]) {
00081                 render.pal.changed = true;
00082                 render.pal.modified[i] = 1;
00083                 render.pal.lut.b32[i] = newPal;
00084             }
00085         }
00086         break;
00087     }
00088     /* Setup pal index to startup values */
00089     render.pal.first=256;
00090     render.pal.last=0;
00091 }
00092 
00093 uint32_t GFX_palette32bpp[256] = {0};
00094 
00095 unsigned int GFX_GetBShift();
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)
00124 # define sse2_available (1) /* SSE2 is always available on x86_64 */
00125 #endif
00126 /*END HACK*/
00127 
00128 static void RENDER_StartLineHandler(const void * s) {
00129     if (s) {
00130         const Bitu *src = (Bitu*)s;
00131         Bitu *cache = (Bitu*)(render.scale.cacheRead);
00132         Bits count = (Bits)render.src.start;
00133 #if defined(__SSE__)
00134         if (sse2_available) {
00135 #if defined (_MSC_VER)
00136 #define SIZEOF_INT_P sizeof(*src)
00137 #endif
00138             static const Bitu simd_inc = 16/SIZEOF_INT_P;
00139             while (count >= (Bits)simd_inc) {
00140                 __m128i v = _mm_loadu_si128((const __m128i*)src);
00141                 __m128i c = _mm_loadu_si128((const __m128i*)cache);
00142                 __m128i cmp = _mm_cmpeq_epi32(v, c);
00143                 if (GCC_UNLIKELY(_mm_movemask_epi8(cmp) != 0xFFFF))
00144                     goto cacheMiss;
00145                 count-=(Bits)simd_inc; src+=simd_inc; cache+=simd_inc;
00146             }
00147         }
00148         else
00149 #endif
00150         {
00151             while (count) {
00152                 if (GCC_UNLIKELY(src[0] != cache[0]))
00153                     goto cacheMiss;
00154                 count--; src++; cache++;
00155             }
00156         }
00157     }
00158 /* cacheHit */
00159     render.scale.cacheRead += render.scale.cachePitch;
00160     Scaler_ChangedLines[0] += Scaler_Aspect[ render.scale.inLine ];
00161     render.scale.inLine++;
00162     render.scale.outLine++;
00163     return;
00164 cacheMiss:
00165     if (!GFX_StartUpdate( render.scale.outWrite, render.scale.outPitch )) {
00166         RENDER_DrawLine = RENDER_EmptyLineHandler;
00167         return;
00168     }
00169     render.scale.outWrite += render.scale.outPitch * Scaler_ChangedLines[0];
00170     RENDER_DrawLine = render.scale.lineHandler;
00171     RENDER_DrawLine( s );
00172 }
00173 
00174 static void RENDER_FinishLineHandler(const void * s) {
00175     if (s) {
00176         const Bitu *src = (Bitu*)s;
00177         Bitu *cache = (Bitu*)(render.scale.cacheRead);
00178         for (Bitu x=render.src.start;x>0;) {
00179             cache[0] = src[0];
00180             x--; src++; cache++;
00181         }
00182     }
00183     render.scale.cacheRead += render.scale.cachePitch;
00184 }
00185 
00186 
00187 static void RENDER_ClearCacheHandler(const void * src) {
00188     Bitu x, width;
00189     Bit32u *srcLine, *cacheLine;
00190     srcLine = (Bit32u *)src;
00191     cacheLine = (Bit32u *)render.scale.cacheRead;
00192     width = render.scale.cachePitch / 4;
00193     for (x=0;x<width;x++)
00194         cacheLine[x] = ~srcLine[x];
00195     render.scale.lineHandler( src );
00196 }
00197 
00198 extern void GFX_SetTitle(Bit32s cycles,Bits frameskip,Bits timing,bool paused);
00199 
00200 bool RENDER_StartUpdate(void) {
00201     if (GCC_UNLIKELY(render.updating))
00202         return false;
00203     if (GCC_UNLIKELY(!render.active))
00204         return false;
00205     if (GCC_UNLIKELY(render.frameskip.count<render.frameskip.max)) {
00206         render.frameskip.count++;
00207         return false;
00208     }
00209     render.frameskip.count=0;
00210     if (render.scale.inMode == scalerMode8) {
00211         Check_Palette();
00212     }
00213     render.scale.inLine = 0;
00214     render.scale.outLine = 0;
00215     render.scale.cacheRead = (Bit8u*)&scalerSourceCache;
00216     render.scale.outWrite = 0;
00217     render.scale.outPitch = 0;
00218     Scaler_ChangedLines[0] = 0;
00219     Scaler_ChangedLineIndex = 0;
00220     /* Clearing the cache will first process the line to make sure it's never the same */
00221     if (GCC_UNLIKELY( render.scale.clearCache) ) {
00222 //      LOG_MSG("Clearing cache");
00223         //Will always have to update the screen with this one anyway, so let's update already
00224         if (GCC_UNLIKELY(!GFX_StartUpdate( render.scale.outWrite, render.scale.outPitch )))
00225             return false;
00226         render.fullFrame = true;
00227         RENDER_DrawLine = RENDER_ClearCacheHandler;
00228     } else {
00229         if (render.pal.changed) {
00230             /* Assume pal changes always do a full screen update anyway */
00231             if (GCC_UNLIKELY(!GFX_StartUpdate( render.scale.outWrite, render.scale.outPitch )))
00232                 return false;
00233             RENDER_DrawLine = render.scale.linePalHandler;
00234             render.fullFrame = true;
00235         } else {
00236             RENDER_DrawLine = RENDER_StartLineHandler;
00237             if (GCC_UNLIKELY(CaptureState & (CAPTURE_IMAGE|CAPTURE_VIDEO))) 
00238                 render.fullFrame = true;
00239             else
00240                 render.fullFrame = false;
00241         }
00242     }
00243     render.updating = true;
00244     return true;
00245 }
00246 
00247 static void RENDER_Halt( void ) {
00248     RENDER_DrawLine = RENDER_EmptyLineHandler;
00249     GFX_EndUpdate( 0 );
00250     render.updating=false;
00251     render.active=false;
00252 }
00253 
00254 extern Bitu PIC_Ticks;
00255 extern bool pause_on_vsync;
00256 void PauseDOSBox(bool pressed);
00257 
00258 void RENDER_EndUpdate( bool abort ) {
00259     if (GCC_UNLIKELY(!render.updating))
00260         return;
00261 
00262     if (!abort && render.active && RENDER_DrawLine == RENDER_ClearCacheHandler)
00263         render.scale.clearCache = false;
00264 
00265     RENDER_DrawLine = RENDER_EmptyLineHandler;
00266     if (GCC_UNLIKELY(CaptureState & (CAPTURE_IMAGE|CAPTURE_VIDEO))) {
00267         Bitu pitch, flags;
00268         flags = 0;
00269         if (render.src.dblw != render.src.dblh) {
00270             if (render.src.dblw) flags|=CAPTURE_FLAG_DBLW;
00271             if (render.src.dblh) flags|=CAPTURE_FLAG_DBLH;
00272         }
00273         float fps = render.src.fps;
00274         pitch = render.scale.cachePitch;
00275         if (render.frameskip.max)
00276             fps /= 1+render.frameskip.max;
00277         CAPTURE_AddImage( render.src.width, render.src.height, render.src.bpp, pitch,
00278             flags, fps, (Bit8u *)&scalerSourceCache, (Bit8u*)&render.pal.rgb );
00279     }
00280     if ( render.scale.outWrite ) {
00281         GFX_EndUpdate( abort? NULL : Scaler_ChangedLines );
00282         render.frameskip.hadSkip[render.frameskip.index] = 0;
00283     } else {
00284 #if 0
00285         Bitu total = 0, i;
00286         render.frameskip.hadSkip[render.frameskip.index] = 1;
00287         for (i = 0;i<RENDER_SKIP_CACHE;i++) 
00288             total += render.frameskip.hadSkip[i];
00289         LOG_MSG( "Skipped frame %d %d", PIC_Ticks, (total * 100) / RENDER_SKIP_CACHE );
00290 #endif
00291         // Force output to update the screen even if nothing changed...
00292         // works only with Direct3D output (GFX_StartUpdate() was probably not even called)
00293         if (render.forceUpdate) GFX_EndUpdate( 0 );
00294     }
00295     render.frameskip.index = (render.frameskip.index + 1) & (RENDER_SKIP_CACHE - 1);
00296     render.updating=false;
00297 
00298     if (pause_on_vsync) {
00299         pause_on_vsync = false;
00300         PauseDOSBox(true);
00301     }
00302 }
00303 
00304 static Bitu MakeAspectTable(Bitu skip,Bitu height,double scaley,Bitu miny) {
00305     Bitu i;
00306     double lines=0;
00307     Bitu linesadded=0;
00308     for (i=0;i<skip;i++)
00309         Scaler_Aspect[i] = 0;
00310 
00311     height += skip;
00312     for (i=skip;i<height;i++) {
00313         lines += scaley;
00314         if (lines >= miny) {
00315             Bitu templines = (Bitu)lines;
00316             lines -= templines;
00317             linesadded += templines;
00318             Scaler_Aspect[i] = templines;
00319         } else {
00320             Scaler_Aspect[i] = 0;
00321         }
00322     }
00323     return linesadded;
00324 }
00325 
00326 
00327 void RENDER_Reset( void ) {
00328     Bitu width=render.src.width;
00329     Bitu height=render.src.height;
00330     bool dblw=render.src.dblw;
00331     bool dblh=render.src.dblh;
00332 
00333     double gfx_scalew;
00334     double gfx_scaleh;
00335 
00336     if (width == 0 || height == 0)
00337         return;
00338     
00339     Bitu gfx_flags, xscale, yscale;
00340     ScalerSimpleBlock_t     *simpleBlock = &ScaleNormal1x;
00341     ScalerComplexBlock_t    *complexBlock = 0;
00342     if (render.aspect) {
00343         if (render.src.ratio>1.0) {
00344             gfx_scalew = 1;
00345             gfx_scaleh = render.src.ratio;
00346         } else {
00347             gfx_scalew = (1.0/render.src.ratio);
00348             gfx_scaleh = 1;
00349         }
00350     } else {
00351         gfx_scalew = 1;
00352         gfx_scaleh = 1;
00353     }
00354     if ((dblh && dblw) || (render.scale.forced && !dblh && !dblw)) {
00355         /* Initialize always working defaults */
00356         if (render.scale.size == 2)
00357             simpleBlock = &ScaleNormal2x;
00358         else if (render.scale.size == 3)
00359             simpleBlock = &ScaleNormal3x;
00360         else if (render.scale.size == 1 && !(dblh || dblw) && render.scale.hardware)
00361             simpleBlock = &ScaleNormal1x;
00362         else if (render.scale.size == 4 && !(dblh || dblw) && render.scale.hardware)
00363             simpleBlock = &ScaleNormal2x;
00364         else if (render.scale.size == 6 && !(dblh || dblw) && render.scale.hardware)
00365             simpleBlock = &ScaleNormal3x;
00366         else if (render.scale.size == 4 && !render.scale.hardware)
00367             simpleBlock = &ScaleNormal4x;
00368         else if (render.scale.size == 5 && !render.scale.hardware)
00369             simpleBlock = &ScaleNormal5x;
00370         else if (render.scale.size == 8 && !(dblh || dblw) && render.scale.hardware)
00371             simpleBlock = &ScaleNormal4x;
00372         else if (render.scale.size == 10 && !(dblh || dblw) && render.scale.hardware)
00373             simpleBlock = &ScaleNormal5x;
00374         else
00375             simpleBlock = &ScaleNormal1x;
00376         /* Maybe override them */
00377 #if RENDER_USE_ADVANCED_SCALERS>0
00378         switch (render.scale.op) {
00379 #if RENDER_USE_ADVANCED_SCALERS>2
00380         case scalerOpAdvInterp:
00381             if (render.scale.size == 2)
00382                 complexBlock = &ScaleAdvInterp2x;
00383             else if (render.scale.size == 3)
00384                 complexBlock = &ScaleAdvInterp3x;
00385             break;
00386         case scalerOpAdvMame:
00387             if (render.scale.size == 2)
00388                 complexBlock = &ScaleAdvMame2x;
00389             else if (render.scale.size == 3)
00390                 complexBlock = &ScaleAdvMame3x;
00391             break;
00392         case scalerOpHQ:
00393             if (render.scale.size == 2)
00394                 complexBlock = &ScaleHQ2x;
00395             else if (render.scale.size == 3)
00396                 complexBlock = &ScaleHQ3x;
00397             break;
00398         case scalerOpSuperSaI:
00399             if (render.scale.size == 2)
00400                 complexBlock = &ScaleSuper2xSaI;
00401             break;
00402         case scalerOpSuperEagle:
00403             if (render.scale.size == 2)
00404                 complexBlock = &ScaleSuperEagle;
00405             break;
00406         case scalerOpSaI:
00407             if (render.scale.size == 2)
00408                 complexBlock = &Scale2xSaI;
00409             break;
00410 #endif
00411         case scalerOpTV:
00412             if (render.scale.size == 2)
00413                 simpleBlock = &ScaleTV2x;
00414             else if (render.scale.size == 3)
00415                 simpleBlock = &ScaleTV3x;
00416             break;
00417         case scalerOpRGB:
00418             if (render.scale.size == 2)
00419                 simpleBlock = &ScaleRGB2x;
00420             else if (render.scale.size == 3)
00421                 simpleBlock = &ScaleRGB3x;
00422             break;
00423         case scalerOpScan:
00424             if (render.scale.size == 2)
00425                 simpleBlock = &ScaleScan2x;
00426             else if (render.scale.size == 3)
00427                 simpleBlock = &ScaleScan3x;
00428             break;
00429         default:
00430             break;
00431         }
00432 #endif
00433     } else if (dblw && !render.scale.hardware) {
00434         simpleBlock = &ScaleNormalDw;
00435     } else if (dblh && !render.scale.hardware) {
00436         simpleBlock = &ScaleNormalDh;
00437     } else  {
00438 forcenormal:
00439         complexBlock = 0;
00440         simpleBlock = &ScaleNormal1x;
00441     }
00442     if (complexBlock) {
00443 #if RENDER_USE_ADVANCED_SCALERS>1
00444         if ((width >= SCALER_COMPLEXWIDTH - 16) || height >= SCALER_COMPLEXHEIGHT - 16) {
00445             LOG_MSG("Scaler can't handle this resolution, going back to normal");
00446             goto forcenormal;
00447         }
00448 #else
00449         goto forcenormal;
00450 #endif
00451         gfx_flags = complexBlock->gfxFlags;
00452         xscale = complexBlock->xscale;  
00453         yscale = complexBlock->yscale;
00454 //      LOG_MSG("Scaler:%s",complexBlock->name);
00455     } else {
00456         gfx_flags = simpleBlock->gfxFlags;
00457         xscale = simpleBlock->xscale;   
00458         yscale = simpleBlock->yscale;
00459 //      LOG_MSG("Scaler:%s",simpleBlock->name);
00460     }
00461     switch (render.src.bpp) {
00462     case 8:
00463         render.src.start = ( render.src.width * 1) / sizeof(Bitu);
00464         if (gfx_flags & GFX_CAN_8)
00465             gfx_flags |= GFX_LOVE_8;
00466         else
00467             gfx_flags |= GFX_LOVE_32;
00468         break;
00469     case 15:
00470         render.src.start = ( render.src.width * 2) / sizeof(Bitu);
00471         gfx_flags |= GFX_LOVE_15;
00472         gfx_flags = (gfx_flags & ~GFX_CAN_8) | GFX_RGBONLY;
00473         break;
00474     case 16:
00475         render.src.start = ( render.src.width * 2) / sizeof(Bitu);
00476         gfx_flags |= GFX_LOVE_16;
00477         gfx_flags = (gfx_flags & ~GFX_CAN_8) | GFX_RGBONLY;
00478         break;
00479     case 32:
00480         render.src.start = ( render.src.width * 4) / sizeof(Bitu);
00481         gfx_flags |= GFX_LOVE_32;
00482         gfx_flags = (gfx_flags & ~GFX_CAN_8) | GFX_RGBONLY;
00483         break;
00484     default:
00485         render.src.start = ( render.src.width * 1) / sizeof(Bitu);
00486         if (gfx_flags & GFX_CAN_8)
00487             gfx_flags |= GFX_LOVE_8;
00488         else
00489             gfx_flags |= GFX_LOVE_32;
00490         break;
00491     }
00492 #if !defined(C_SDL2)
00493     gfx_flags=GFX_GetBestMode(gfx_flags);
00494 #endif
00495     if (!gfx_flags) {
00496         if (!complexBlock && simpleBlock == &ScaleNormal1x) 
00497             E_Exit("Failed to create a rendering output");
00498         else 
00499             goto forcenormal;
00500     }
00501     width *= xscale;
00502     Bitu skip = complexBlock ? 1 : 0;
00503     if (gfx_flags & GFX_SCALING) {
00504         if(render.scale.size == 1 && render.scale.hardware) { //hardware_none
00505             if(dblh)
00506             gfx_scaleh *= 1;
00507             if(dblw)
00508             gfx_scalew *= 1;
00509         } else if(render.scale.size == 4 && render.scale.hardware) {
00510             if(dblh)
00511             gfx_scaleh *= 2;
00512             if(dblw)
00513             gfx_scalew *= 2;
00514         } else if(render.scale.size == 6 && render.scale.hardware) {
00515             if(dblh && dblw) {
00516             gfx_scaleh *= 3; gfx_scalew *= 3;
00517             } else if(dblh) {
00518             gfx_scaleh *= 2;
00519             } else if(dblw)
00520             gfx_scalew *= 2;
00521         } else if(render.scale.size == 8 && render.scale.hardware) { //hardware4x
00522             if(dblh)
00523             gfx_scaleh *= 4;
00524             if(dblw)
00525             gfx_scalew *= 4;
00526         } else if(render.scale.size == 10 && render.scale.hardware) { //hardware5x
00527             if(dblh && dblw) {
00528             gfx_scaleh *= 5; gfx_scalew *= 5;
00529             } else if(dblh) {
00530             gfx_scaleh *= 4;
00531             } else if(dblw)
00532             gfx_scalew *= 4;
00533         }
00534         height = MakeAspectTable(skip, render.src.height, yscale, yscale );
00535     } else {
00536         // Print a warning when hardware scalers are selected, hopefully the first
00537         // video mode will not have dblh or dblw or AR will be wrong
00538         if (render.scale.hardware) {
00539             LOG_MSG("Output does not support hardware scaling, switching to normal scalers");
00540             render.scale.hardware=false;
00541         }
00542         if ((gfx_flags & GFX_CAN_RANDOM) && gfx_scaleh > 1) {
00543             gfx_scaleh *= yscale;
00544             height = MakeAspectTable( skip, render.src.height, gfx_scaleh, yscale );
00545         } else {
00546             gfx_flags &= ~GFX_CAN_RANDOM;       //Hardware surface when possible
00547             height = MakeAspectTable( skip, render.src.height, yscale, yscale);
00548         }
00549     }
00550 /* Setup the scaler variables */
00551     gfx_flags=GFX_SetSize(width,height,gfx_flags,gfx_scalew,gfx_scaleh,&RENDER_CallBack);
00552     if (gfx_flags & GFX_CAN_8)
00553         render.scale.outMode = scalerMode8;
00554     else if (gfx_flags & GFX_CAN_15)
00555         render.scale.outMode = scalerMode15;
00556     else if (gfx_flags & GFX_CAN_16)
00557         render.scale.outMode = scalerMode16;
00558     else if (gfx_flags & GFX_CAN_32)
00559         render.scale.outMode = scalerMode32;
00560     else 
00561         E_Exit("Failed to create a rendering output");
00562     ScalerLineBlock_t *lineBlock;
00563     if (gfx_flags & GFX_HARDWARE) {
00564 #if RENDER_USE_ADVANCED_SCALERS>1
00565         if (complexBlock) {
00566             lineBlock = &ScalerCache;
00567             render.scale.complexHandler = complexBlock->Linear[ render.scale.outMode ];
00568         } else
00569 #endif
00570         {
00571             render.scale.complexHandler = 0;
00572             lineBlock = &simpleBlock->Linear;
00573         }
00574     } else {
00575 #if RENDER_USE_ADVANCED_SCALERS>1
00576         if (complexBlock) {
00577             lineBlock = &ScalerCache;
00578             render.scale.complexHandler = complexBlock->Random[ render.scale.outMode ];
00579         } else
00580 #endif
00581         {
00582             render.scale.complexHandler = 0;
00583             lineBlock = &simpleBlock->Random;
00584         }
00585     }
00586     switch (render.src.bpp) {
00587     case 8:
00588         render.scale.lineHandler = (*lineBlock)[0][render.scale.outMode];
00589         render.scale.linePalHandler = (*lineBlock)[4][render.scale.outMode];
00590         render.scale.inMode = scalerMode8;
00591         render.scale.cachePitch = render.src.width * 1;
00592         break;
00593     case 15:
00594         render.scale.lineHandler = (*lineBlock)[1][render.scale.outMode];
00595         render.scale.linePalHandler = 0;
00596         render.scale.inMode = scalerMode15;
00597         render.scale.cachePitch = render.src.width * 2;
00598         break;
00599     case 16:
00600         render.scale.lineHandler = (*lineBlock)[2][render.scale.outMode];
00601         render.scale.linePalHandler = 0;
00602         render.scale.inMode = scalerMode16;
00603         render.scale.cachePitch = render.src.width * 2;
00604         break;
00605     case 32:
00606         render.scale.lineHandler = (*lineBlock)[3][render.scale.outMode];
00607         render.scale.linePalHandler = 0;
00608         render.scale.inMode = scalerMode32;
00609         render.scale.cachePitch = render.src.width * 4;
00610         break;
00611     default:
00612         //render.src.bpp=8;
00613         render.scale.lineHandler = (*lineBlock)[0][render.scale.outMode];
00614         render.scale.linePalHandler = (*lineBlock)[4][render.scale.outMode];
00615         render.scale.inMode = scalerMode8;
00616         render.scale.cachePitch = render.src.width * 1;
00617         break;
00618         //E_Exit("RENDER:Wrong source bpp %d", render.src.bpp );
00619     }
00620     render.scale.blocks = render.src.width / SCALER_BLOCKSIZE;
00621     render.scale.lastBlock = render.src.width % SCALER_BLOCKSIZE;
00622     render.scale.inHeight = render.src.height;
00623     /* Reset the palette change detection to it's initial value */
00624     render.pal.first= 0;
00625     render.pal.last = 255;
00626     render.pal.changed = false;
00627     memset(render.pal.modified, 0, sizeof(render.pal.modified));
00628     //Finish this frame using a copy only handler
00629     RENDER_DrawLine = RENDER_FinishLineHandler;
00630     render.scale.outWrite = 0;
00631     /* Signal the next frame to first reinit the cache */
00632     render.scale.clearCache = true;
00633     render.active=true;
00634 
00635     last_gfx_flags = gfx_flags;
00636 }
00637 
00638 void RENDER_CallBack( GFX_CallBackFunctions_t function ) {
00639     if (function == GFX_CallBackStop) {
00640         RENDER_Halt( ); 
00641         return;
00642     } else if (function == GFX_CallBackRedraw) {
00643         render.scale.clearCache = true;
00644         return;
00645     } else if ( function == GFX_CallBackReset) {
00646         GFX_EndUpdate( 0 ); 
00647         RENDER_Reset();
00648     } else {
00649         E_Exit("Unhandled GFX_CallBackReset %d", function );
00650     }
00651 }
00652 
00653 void RENDER_SetSize(Bitu width,Bitu height,Bitu bpp,float fps,double scrn_ratio) {
00654     RENDER_Halt( );
00655     if (!width || !height || width > SCALER_MAXWIDTH || height > SCALER_MAXHEIGHT) { 
00656         return; 
00657     }
00658 
00659     // figure out doublewidth/height values
00660     bool dblw = false;
00661     bool dblh = false;
00662     double ratio = (((double)width)/((double)height))/scrn_ratio;
00663     if(ratio > 1.6) {
00664         dblh=true;
00665         ratio /= 2.0;
00666     } else if(ratio < 0.75) {
00667         dblw=true;
00668         ratio *= 2.0;
00669     } else if(!dblw && !dblh && (width < 370) && (height < 280)) {
00670         dblw=true; dblh=true;
00671     }
00672     LOG_MSG("pixratio %1.3f, dw %s, dh %s",ratio,dblw?"true":"false",dblh?"true":"false");
00673 
00674     if ( ratio > 1.0 ) {
00675         double target = height * ratio + 0.1;
00676         ratio = target / height;
00677     } else {
00678         //This would alter the width of the screen, we don't care about rounding errors here
00679     }
00680     render.src.width=width;
00681     render.src.height=height;
00682     render.src.bpp=bpp;
00683     render.src.dblw=dblw;
00684     render.src.dblh=dblh;
00685     render.src.fps=fps;
00686     render.src.ratio=ratio;
00687     render.src.scrn_ratio=scrn_ratio;
00688     RENDER_Reset( );
00689 }
00690 
00691 //extern void GFX_SetTitle(Bit32s cycles, Bits frameskip, Bits timing, bool paused);
00692 static void IncreaseFrameSkip(bool pressed) {
00693     if (!pressed)
00694         return;
00695     if (render.frameskip.max<10) render.frameskip.max++;
00696     LOG_MSG("Frame Skip at %d",(int)render.frameskip.max);
00697     GFX_SetTitle(-1,(Bits)render.frameskip.max,-1,false);
00698 }
00699 
00700 static void DecreaseFrameSkip(bool pressed) {
00701     if (!pressed)
00702         return;
00703     if (render.frameskip.max>0) render.frameskip.max--;
00704     LOG_MSG("Frame Skip at %d",(int)render.frameskip.max);
00705     GFX_SetTitle(-1,(Bits)render.frameskip.max,-1,false);
00706 }
00707 /* Disabled as I don't want to waste a keybind for that. Might be used in the future (Qbix)
00708 static void ChangeScaler(bool pressed) {
00709     if (!pressed)
00710         return;
00711     render.scale.op = (scalerOperation)((int)render.scale.op+1);
00712     if((render.scale.op) >= scalerLast || render.scale.size == 1) {
00713         render.scale.op = (scalerOperation)0;
00714         if(++render.scale.size > 3)
00715             render.scale.size = 1;
00716     }
00717     RENDER_CallBack( GFX_CallBackReset );
00718 } */
00719 
00720 #include "vga.h"
00721 
00722 bool RENDER_GetAutofit(void) {
00723     return render.autofit;
00724 }
00725 
00726 bool RENDER_GetAspect(void) {
00727     return render.aspect;
00728 }
00729 
00730 void RENDER_SetForceUpdate(bool f) {
00731     render.forceUpdate = f;
00732 }
00733 
00734 void RENDER_UpdateFrameskipMenu(void) {
00735     char tmp[64];
00736 
00737     for (unsigned int f=0;f <= 10;f++) {
00738         sprintf(tmp,"frameskip_%u",f);
00739         DOSBoxMenu::item &item = mainMenu.get_item(tmp);
00740         item.check(render.frameskip.max == f);
00741     }
00742 }
00743 
00744 void VGA_SetupDrawing(Bitu /*val*/);
00745 
00746 void RENDER_OnSectionPropChange(Section *x) {
00747     (void)x;//UNUSED
00748     Section_prop * section = static_cast<Section_prop *>(control->GetSection("render"));
00749 
00750     bool p_doublescan = vga.draw.doublescan_set;
00751     bool p_char9 = vga.draw.char9_set;
00752     bool p_aspect = render.aspect;
00753 
00754     render.aspect = section->Get_bool("aspect");
00755     render.frameskip.max = (Bitu)section->Get_int("frameskip");
00756 
00757     vga.draw.doublescan_set=section->Get_bool("doublescan");
00758     vga.draw.char9_set=section->Get_bool("char9");
00759 
00760     if (render.aspect != p_aspect || vga.draw.doublescan_set != p_doublescan || vga.draw.char9_set != p_char9)
00761         RENDER_CallBack(GFX_CallBackReset);
00762     if (vga.draw.doublescan_set != p_doublescan || vga.draw.char9_set != p_char9)
00763         VGA_StartResize();
00764 
00765     mainMenu.get_item("vga_9widetext").check(vga.draw.char9_set).refresh_item(mainMenu);
00766     mainMenu.get_item("doublescan").check(vga.draw.doublescan_set).refresh_item(mainMenu);
00767 
00768     RENDER_UpdateFrameskipMenu();
00769 }
00770 
00771 std::string RENDER_GetScaler(void) {
00772     Section_prop * section=static_cast<Section_prop *>(control->GetSection("render"));
00773     Prop_multival* prop = section->Get_multival("scaler");
00774     return prop->GetSection()->Get_string("type");
00775 }
00776 
00777 extern const char *scaler_menu_opts[][2];
00778 
00779 void RENDER_UpdateScalerMenu(void) {
00780     const std::string scaler = RENDER_GetScaler();
00781 
00782     for (size_t i=0;scaler_menu_opts[i][0] != NULL;i++) {
00783         const std::string name = std::string("scaler_set_") + scaler_menu_opts[i][0];
00784         mainMenu.get_item(name).check(scaler == scaler_menu_opts[i][0]).refresh_item(mainMenu);
00785     }
00786 }
00787 
00788 void RENDER_UpdateFromScalerSetting(void) {
00789     Section_prop * section=static_cast<Section_prop *>(control->GetSection("render"));
00790     Prop_multival* prop = section->Get_multival("scaler");
00791     std::string f = prop->GetSection()->Get_string("force");
00792     std::string scaler = prop->GetSection()->Get_string("type");
00793 
00794     render.scale.forced = false;
00795     if(f == "forced") render.scale.forced = true;
00796    
00797     if (scaler == "none") { render.scale.op = scalerOpNormal; render.scale.size = 1; render.scale.hardware=false; }
00798     else if (scaler == "normal2x") { render.scale.op = scalerOpNormal; render.scale.size = 2; render.scale.hardware=false; }
00799     else if (scaler == "normal3x") { render.scale.op = scalerOpNormal; render.scale.size = 3; render.scale.hardware=false; }
00800     else if (scaler == "normal4x") { render.scale.op = scalerOpNormal; render.scale.size = 4; render.scale.hardware=false; }
00801     else if (scaler == "normal5x") { render.scale.op = scalerOpNormal; render.scale.size = 5; render.scale.hardware=false; }
00802 #if RENDER_USE_ADVANCED_SCALERS>2
00803     else if (scaler == "advmame2x") { render.scale.op = scalerOpAdvMame; render.scale.size = 2; render.scale.hardware=false; }
00804     else if (scaler == "advmame3x") { render.scale.op = scalerOpAdvMame; render.scale.size = 3; render.scale.hardware=false; }
00805     else if (scaler == "advinterp2x") { render.scale.op = scalerOpAdvInterp; render.scale.size = 2; render.scale.hardware=false; }
00806     else if (scaler == "advinterp3x") { render.scale.op = scalerOpAdvInterp; render.scale.size = 3; render.scale.hardware=false; }
00807     else if (scaler == "hq2x") { render.scale.op = scalerOpHQ; render.scale.size = 2; render.scale.hardware=false; }
00808     else if (scaler == "hq3x") { render.scale.op = scalerOpHQ; render.scale.size = 3; render.scale.hardware=false; }
00809     else if (scaler == "2xsai") { render.scale.op = scalerOpSaI; render.scale.size = 2; render.scale.hardware=false; }
00810     else if (scaler == "super2xsai") { render.scale.op = scalerOpSuperSaI; render.scale.size = 2; render.scale.hardware=false; }
00811     else if (scaler == "supereagle") { render.scale.op = scalerOpSuperEagle; render.scale.size = 2; render.scale.hardware=false; }
00812 #endif
00813 #if RENDER_USE_ADVANCED_SCALERS>0
00814     else if (scaler == "tv2x") { render.scale.op = scalerOpTV; render.scale.size = 2; render.scale.hardware=false; }
00815     else if (scaler == "tv3x") { render.scale.op = scalerOpTV; render.scale.size = 3; render.scale.hardware=false; }
00816     else if (scaler == "rgb2x"){ render.scale.op = scalerOpRGB; render.scale.size = 2; render.scale.hardware=false; }
00817     else if (scaler == "rgb3x"){ render.scale.op = scalerOpRGB; render.scale.size = 3; render.scale.hardware=false; }
00818     else if (scaler == "scan2x"){ render.scale.op = scalerOpScan; render.scale.size = 2; render.scale.hardware=false; }
00819     else if (scaler == "scan3x"){ render.scale.op = scalerOpScan; render.scale.size = 3; render.scale.hardware=false; }
00820 #endif
00821     else if (scaler == "hardware_none") { render.scale.op = scalerOpNormal; render.scale.size = 1; render.scale.hardware=true; }
00822     else if (scaler == "hardware2x") { render.scale.op = scalerOpNormal; render.scale.size = 4; render.scale.hardware=true; }
00823     else if (scaler == "hardware3x") { render.scale.op = scalerOpNormal; render.scale.size = 6; render.scale.hardware=true; }
00824     else if (scaler == "hardware4x") { render.scale.op = scalerOpNormal; render.scale.size = 8; render.scale.hardware=true; }
00825     else if (scaler == "hardware5x") { render.scale.op = scalerOpNormal; render.scale.size = 10; render.scale.hardware=true; }
00826 }
00827 
00828 void RENDER_Init() {
00829     Section_prop * section=static_cast<Section_prop *>(control->GetSection("render"));
00830 
00831     LOG(LOG_MISC,LOG_DEBUG)("Initializing renderer");
00832 
00833     control->GetSection("render")->onpropchange.push_back(&RENDER_OnSectionPropChange);
00834 
00835     vga.draw.doublescan_set=section->Get_bool("doublescan");
00836     vga.draw.char9_set=section->Get_bool("char9");
00837 
00838     mainMenu.get_item("vga_9widetext").check(vga.draw.char9_set).refresh_item(mainMenu);
00839     mainMenu.get_item("doublescan").check(vga.draw.doublescan_set).refresh_item(mainMenu);
00840 
00841     //For restarting the renderer.
00842     static bool running = false;
00843     bool aspect = render.aspect;
00844     Bitu scalersize = render.scale.size;
00845     bool scalerforced = render.scale.forced;
00846     scalerOperation_t scaleOp = render.scale.op;
00847 
00848     render.scale.cacheRead = NULL;
00849     render.scale.outWrite = NULL;
00850 
00851     render.pal.first=0;
00852     render.pal.last=255;
00853     render.aspect=section->Get_bool("aspect");
00854     render.frameskip.max=(Bitu)section->Get_int("frameskip");
00855 
00856     RENDER_UpdateFrameskipMenu();
00857 
00858     /* BUG FIX: Some people's dosbox.conf files have frameskip=-1 WTF?? */
00859     /* without this fix, nothing displays, EVER */
00860     if ((int)render.frameskip.max < 0) render.frameskip.max = 0;
00861                                 
00862     render.frameskip.count=0;
00863     render.forceUpdate=false;
00864     std::string cline;
00865     std::string scaler;
00866     //Check for commandline paramters and parse them through the configclass so they get checked against allowed values
00867     if (control->cmdline->FindString("-scaler",cline,false)) {
00868         section->HandleInputline(std::string("scaler=") + cline);
00869     } else if (control->cmdline->FindString("-forcescaler",cline,false)) {
00870         section->HandleInputline(std::string("scaler=") + cline + " forced");
00871     }
00872 
00873     RENDER_UpdateFromScalerSetting();
00874 
00875     render.autofit=section->Get_bool("autofit");
00876 
00877 
00878     //If something changed that needs a ReInit
00879     // Only ReInit when there is a src.bpp (fixes crashes on startup and directly changing the scaler without a screen specified yet)
00880     if(running && render.src.bpp && ((render.aspect != aspect) || (render.scale.op != scaleOp) || 
00881                   (render.scale.size != scalersize) || (render.scale.forced != scalerforced) ||
00882                    render.scale.forced))
00883         RENDER_CallBack( GFX_CallBackReset );
00884 
00885     if(!running) render.updating=true;
00886     running = true;
00887 
00888     MAPPER_AddHandler(DecreaseFrameSkip,MK_nothing,0,"decfskip","Dec Fskip");
00889     MAPPER_AddHandler(IncreaseFrameSkip,MK_nothing,0,"incfskip","Inc Fskip");
00890 
00891     GFX_SetTitle(-1,(Bits)render.frameskip.max,-1,false);
00892 
00893     RENDER_UpdateScalerMenu();
00894 }
00895