DOSBox-X
|
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 }