1 /*
2  *  Copyright (C) 2002-2010  The DOSBox Team
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18 
19 /* $Id: render.cpp,v 1.60 2009-04-26 19:14:50 harekiet Exp $ */
20 
21 #include <sys/types.h>
22 #include <assert.h>
23 #include <math.h>
24 
25 #include "dosbox.h"
26 #include "video.h"
27 #include "render.h"
28 #include "setup.h"
29 #include "control.h"
30 #include "mapper.h"
31 #include "cross.h"
32 #include "hardware.h"
33 #include "support.h"
34 
35 #include "render_scalers.h"
36 
37 Render_t render;
38 ScalerLineHandler_t RENDER_DrawLine;
39 
40 static void RENDER_CallBack( GFX_CallBackFunctions_t function );
41 
Check_Palette(void)42 static void Check_Palette(void) {
43 	/* Clean up any previous changed palette data */
44 	if (render.pal.changed) {
45 		memset(render.pal.modified, 0, sizeof(render.pal.modified));
46 		render.pal.changed = false;
47 	}
48 	if (render.pal.first>render.pal.last)
49 		return;
50 	Bitu i;
51 	switch (render.scale.outMode) {
52 	case scalerMode8:
53 		GFX_SetPalette(render.pal.first,render.pal.last-render.pal.first+1,(GFX_PalEntry *)&render.pal.rgb[render.pal.first]);
54 		break;
55 	case scalerMode15:
56 	case scalerMode16:
57 		for (i=render.pal.first;i<=render.pal.last;i++) {
58 			Bit8u r=render.pal.rgb[i].red;
59 			Bit8u g=render.pal.rgb[i].green;
60 			Bit8u b=render.pal.rgb[i].blue;
61 			Bit16u newPal = GFX_GetRGB(r,g,b);
62 			if (newPal != render.pal.lut.b16[i]) {
63 				render.pal.changed = true;
64 				render.pal.modified[i] = 1;
65 				render.pal.lut.b16[i] = newPal;
66 			}
67 		}
68 		break;
69 	case scalerMode32:
70 	default:
71 		for (i=render.pal.first;i<=render.pal.last;i++) {
72 			Bit8u r=render.pal.rgb[i].red;
73 			Bit8u g=render.pal.rgb[i].green;
74 			Bit8u b=render.pal.rgb[i].blue;
75 			Bit32u newPal = GFX_GetRGB(r,g,b);
76 			if (newPal != render.pal.lut.b32[i]) {
77 				render.pal.changed = true;
78 				render.pal.modified[i] = 1;
79 				render.pal.lut.b32[i] = newPal;
80 			}
81 		}
82 		break;
83 	}
84 	/* Setup pal index to startup values */
85 	render.pal.first=256;
86 	render.pal.last=0;
87 }
88 
RENDER_SetPal(Bit8u entry,Bit8u red,Bit8u green,Bit8u blue)89 void RENDER_SetPal(Bit8u entry,Bit8u red,Bit8u green,Bit8u blue) {
90 	render.pal.rgb[entry].red=red;
91 	render.pal.rgb[entry].green=green;
92 	render.pal.rgb[entry].blue=blue;
93 	if (render.pal.first>entry) render.pal.first=entry;
94 	if (render.pal.last<entry) render.pal.last=entry;
95 }
96 
RENDER_EmptyLineHandler(const void * src)97 static void RENDER_EmptyLineHandler(const void * src) {
98 }
99 
RENDER_StartLineHandler(const void * s)100 static void RENDER_StartLineHandler(const void * s) {
101 	if (s) {
102 		const Bitu *src = (Bitu*)s;
103 		Bitu *cache = (Bitu*)(render.scale.cacheRead);
104 		for (Bits x=render.src.start;x>0;) {
105 			if (GCC_UNLIKELY(src[0] != cache[0])) {
106 				if (!GFX_StartUpdate( render.scale.outWrite, render.scale.outPitch )) {
107 					RENDER_DrawLine = RENDER_EmptyLineHandler;
108 					return;
109 				}
110 				render.scale.outWrite += render.scale.outPitch * Scaler_ChangedLines[0];
111 				RENDER_DrawLine = render.scale.lineHandler;
112 				RENDER_DrawLine( s );
113 				return;
114 			}
115 			x--; src++; cache++;
116 		}
117 	}
118 	render.scale.cacheRead += render.scale.cachePitch;
119 	Scaler_ChangedLines[0] += Scaler_Aspect[ render.scale.inLine ];
120 	render.scale.inLine++;
121 	render.scale.outLine++;
122 }
123 
RENDER_FinishLineHandler(const void * s)124 static void RENDER_FinishLineHandler(const void * s) {
125 	if (s) {
126 		const Bitu *src = (Bitu*)s;
127 		Bitu *cache = (Bitu*)(render.scale.cacheRead);
128 		for (Bits x=render.src.start;x>0;) {
129 			cache[0] = src[0];
130 			x--; src++; cache++;
131 		}
132 	}
133 	render.scale.cacheRead += render.scale.cachePitch;
134 }
135 
136 
RENDER_ClearCacheHandler(const void * src)137 static void RENDER_ClearCacheHandler(const void * src) {
138 	Bitu x, width;
139 	Bit32u *srcLine, *cacheLine;
140 	srcLine = (Bit32u *)src;
141 	cacheLine = (Bit32u *)render.scale.cacheRead;
142 	width = render.scale.cachePitch / 4;
143 	for (x=0;x<width;x++)
144 		cacheLine[x] = ~srcLine[x];
145 	render.scale.lineHandler( src );
146 }
147 
RENDER_StartUpdate(void)148 bool RENDER_StartUpdate(void) {
149 	if (GCC_UNLIKELY(render.updating))
150 		return false;
151 	if (GCC_UNLIKELY(!render.active))
152 		return false;
153 	if (GCC_UNLIKELY(render.frameskip.count<render.frameskip.max)) {
154 		render.frameskip.count++;
155 		return false;
156 	}
157 	render.frameskip.count=0;
158 	if (render.scale.inMode == scalerMode8) {
159 		Check_Palette();
160 	}
161 	render.scale.inLine = 0;
162 	render.scale.outLine = 0;
163 	render.scale.cacheRead = (Bit8u*)&scalerSourceCache;
164 	render.scale.outWrite = 0;
165 	render.scale.outPitch = 0;
166 	Scaler_ChangedLines[0] = 0;
167 	Scaler_ChangedLineIndex = 0;
168 	/* Clearing the cache will first process the line to make sure it's never the same */
169 	if (GCC_UNLIKELY( render.scale.clearCache) ) {
170 //		LOG_MSG("Clearing cache");
171 		//Will always have to update the screen with this one anyway, so let's update already
172 		if (GCC_UNLIKELY(!GFX_StartUpdate( render.scale.outWrite, render.scale.outPitch )))
173 			return false;
174 		render.fullFrame = true;
175 		render.scale.clearCache = false;
176 		RENDER_DrawLine = RENDER_ClearCacheHandler;
177 	} else {
178 		if (render.pal.changed) {
179 			/* Assume pal changes always do a full screen update anyway */
180 			if (GCC_UNLIKELY(!GFX_StartUpdate( render.scale.outWrite, render.scale.outPitch )))
181 				return false;
182 			RENDER_DrawLine = render.scale.linePalHandler;
183 			render.fullFrame = true;
184 		} else {
185 			RENDER_DrawLine = RENDER_StartLineHandler;
186 			if (GCC_UNLIKELY(CaptureState & (CAPTURE_IMAGE|CAPTURE_VIDEO)))
187 				render.fullFrame = true;
188 			else
189 				render.fullFrame = false;
190 		}
191 	}
192 	render.updating = true;
193 	return true;
194 }
195 
RENDER_Halt(void)196 static void RENDER_Halt( void ) {
197 	RENDER_DrawLine = RENDER_EmptyLineHandler;
198 	GFX_EndUpdate( 0 );
199 	render.updating=false;
200 	render.active=false;
201 }
202 
203 extern Bitu PIC_Ticks;
RENDER_EndUpdate(bool abort)204 void RENDER_EndUpdate( bool abort ) {
205 	if (GCC_UNLIKELY(!render.updating))
206 		return;
207 	RENDER_DrawLine = RENDER_EmptyLineHandler;
208 	if (GCC_UNLIKELY(CaptureState & (CAPTURE_IMAGE|CAPTURE_VIDEO))) {
209 		Bitu pitch, flags;
210 		flags = 0;
211 		if (render.src.dblw != render.src.dblh) {
212 			if (render.src.dblw) flags|=CAPTURE_FLAG_DBLW;
213 			if (render.src.dblh) flags|=CAPTURE_FLAG_DBLH;
214 		}
215 		float fps = render.src.fps;
216 		pitch = render.scale.cachePitch;
217 		if (render.frameskip.max)
218 			fps /= 1+render.frameskip.max;
219 		CAPTURE_AddImage( render.src.width, render.src.height, render.src.bpp, pitch,
220 			flags, fps, (Bit8u *)&scalerSourceCache, (Bit8u*)&render.pal.rgb );
221 	}
222 	if ( render.scale.outWrite ) {
223 		GFX_EndUpdate( abort? NULL : Scaler_ChangedLines );
224 		render.frameskip.hadSkip[render.frameskip.index] = 0;
225 	} else {
226 #if 0
227 		Bitu total = 0, i;
228 		render.frameskip.hadSkip[render.frameskip.index] = 1;
229 		for (i = 0;i<RENDER_SKIP_CACHE;i++)
230 			total += render.frameskip.hadSkip[i];
231 		LOG_MSG( "Skipped frame %d %d", PIC_Ticks, (total * 100) / RENDER_SKIP_CACHE );
232 #endif
233 	}
234 	render.frameskip.index = (render.frameskip.index + 1) & (RENDER_SKIP_CACHE - 1);
235 	render.updating=false;
236 }
237 
MakeAspectTable(Bitu skip,Bitu height,double scaley,Bitu miny)238 static Bitu MakeAspectTable(Bitu skip,Bitu height,double scaley,Bitu miny) {
239 	Bitu i;
240 	double lines=0;
241 	Bitu linesadded=0;
242 	for (i=0;i<skip;i++)
243 		Scaler_Aspect[i] = 0;
244 
245 	height += skip;
246 	for (i=skip;i<height;i++) {
247 		lines += scaley;
248 		if (lines >= miny) {
249 			Bitu templines = (Bitu)lines;
250 			lines -= templines;
251 			linesadded += templines;
252 			Scaler_Aspect[i] = templines;
253 		} else {
254 			Scaler_Aspect[i] = 0;
255 		}
256 	}
257 	return linesadded;
258 }
259 
260 
RENDER_Reset(void)261 static void RENDER_Reset( void ) {
262 	Bitu width=render.src.width;
263 	Bitu height=render.src.height;
264 	bool dblw=render.src.dblw;
265 	bool dblh=render.src.dblh;
266 
267 	double gfx_scalew;
268 	double gfx_scaleh;
269 
270 	Bitu gfx_flags, xscale, yscale;
271 	ScalerSimpleBlock_t		*simpleBlock = &ScaleNormal1x;
272 	ScalerComplexBlock_t	*complexBlock = 0;
273 	if (render.aspect) {
274 		if (render.src.ratio>1.0) {
275 			gfx_scalew = 1;
276 			gfx_scaleh = render.src.ratio;
277 		} else {
278 			gfx_scalew = (1/render.src.ratio);
279 			gfx_scaleh = 1;
280 		}
281 	} else {
282 		gfx_scalew = 1;
283 		gfx_scaleh = 1;
284 	}
285 	if ((dblh && dblw) || (render.scale.forced && !dblh && !dblw)) {
286 		/* Initialize always working defaults */
287 		if (render.scale.size == 2)
288 			simpleBlock = &ScaleNormal2x;
289 		else if (render.scale.size == 3)
290 			simpleBlock = &ScaleNormal3x;
291 		else
292 			simpleBlock = &ScaleNormal1x;
293 		/* Maybe override them */
294 #if RENDER_USE_ADVANCED_SCALERS>0
295 		switch (render.scale.op) {
296 #if RENDER_USE_ADVANCED_SCALERS>2
297 		case scalerOpAdvInterp:
298 			if (render.scale.size == 2)
299 				complexBlock = &ScaleAdvInterp2x;
300 			else if (render.scale.size == 3)
301 				complexBlock = &ScaleAdvInterp3x;
302 			break;
303 		case scalerOpAdvMame:
304 			if (render.scale.size == 2)
305 				complexBlock = &ScaleAdvMame2x;
306 			else if (render.scale.size == 3)
307 				complexBlock = &ScaleAdvMame3x;
308 			break;
309 		case scalerOpHQ:
310 			if (render.scale.size == 2)
311 				complexBlock = &ScaleHQ2x;
312 			else if (render.scale.size == 3)
313 				complexBlock = &ScaleHQ3x;
314 			break;
315 		case scalerOpSuperSaI:
316 			if (render.scale.size == 2)
317 				complexBlock = &ScaleSuper2xSaI;
318 			break;
319 		case scalerOpSuperEagle:
320 			if (render.scale.size == 2)
321 				complexBlock = &ScaleSuperEagle;
322 			break;
323 		case scalerOpSaI:
324 			if (render.scale.size == 2)
325 				complexBlock = &Scale2xSaI;
326 			break;
327 #endif
328 		case scalerOpTV:
329 			if (render.scale.size == 2)
330 				simpleBlock = &ScaleTV2x;
331 			else if (render.scale.size == 3)
332 				simpleBlock = &ScaleTV3x;
333 			break;
334 		case scalerOpRGB:
335 			if (render.scale.size == 2)
336 				simpleBlock = &ScaleRGB2x;
337 			else if (render.scale.size == 3)
338 				simpleBlock = &ScaleRGB3x;
339 			break;
340 		case scalerOpScan:
341 			if (render.scale.size == 2)
342 				simpleBlock = &ScaleScan2x;
343 			else if (render.scale.size == 3)
344 				simpleBlock = &ScaleScan3x;
345 			break;
346 		default:
347 			break;
348 		}
349 #endif
350 	} else if (dblw) {
351 		simpleBlock = &ScaleNormalDw;
352 	} else if (dblh) {
353 		simpleBlock = &ScaleNormalDh;
354 	} else  {
355 forcenormal:
356 		complexBlock = 0;
357 		simpleBlock = &ScaleNormal1x;
358 	}
359 	if (complexBlock) {
360 #if RENDER_USE_ADVANCED_SCALERS>1
361 		if ((width >= SCALER_COMPLEXWIDTH - 16) || height >= SCALER_COMPLEXHEIGHT - 16) {
362 			LOG_MSG("Scaler can't handle this resolution, going back to normal");
363 			goto forcenormal;
364 		}
365 #else
366 		goto forcenormal;
367 #endif
368 		gfx_flags = complexBlock->gfxFlags;
369 		xscale = complexBlock->xscale;
370 		yscale = complexBlock->yscale;
371 //		LOG_MSG("Scaler:%s",complexBlock->name);
372 	} else {
373 		gfx_flags = simpleBlock->gfxFlags;
374 		xscale = simpleBlock->xscale;
375 		yscale = simpleBlock->yscale;
376 //		LOG_MSG("Scaler:%s",simpleBlock->name);
377 	}
378 	switch (render.src.bpp) {
379 	case 8:
380 		render.src.start = ( render.src.width * 1) / sizeof(Bitu);
381 		if (gfx_flags & GFX_CAN_8)
382 			gfx_flags |= GFX_LOVE_8;
383 		else
384 			gfx_flags |= GFX_LOVE_32;
385 			break;
386 	case 15:
387 			render.src.start = ( render.src.width * 2) / sizeof(Bitu);
388 			gfx_flags |= GFX_LOVE_15;
389 			gfx_flags = (gfx_flags & ~GFX_CAN_8) | GFX_RGBONLY;
390 			break;
391 	case 16:
392 			render.src.start = ( render.src.width * 2) / sizeof(Bitu);
393 			gfx_flags |= GFX_LOVE_16;
394 			gfx_flags = (gfx_flags & ~GFX_CAN_8) | GFX_RGBONLY;
395 			break;
396 	case 32:
397 			render.src.start = ( render.src.width * 4) / sizeof(Bitu);
398 			gfx_flags |= GFX_LOVE_32;
399 			gfx_flags = (gfx_flags & ~GFX_CAN_8) | GFX_RGBONLY;
400 			break;
401 	}
402 	gfx_flags=GFX_GetBestMode(gfx_flags);
403 	if (!gfx_flags) {
404 		if (!complexBlock && simpleBlock == &ScaleNormal1x)
405 			E_Exit("Failed to create a rendering output");
406 		else
407 			goto forcenormal;
408 	}
409 	width *= xscale;
410 	Bitu skip = complexBlock ? 1 : 0;
411 	if (gfx_flags & GFX_SCALING) {
412 		height = MakeAspectTable(skip, render.src.height, yscale, yscale );
413 	} else {
414 		if ((gfx_flags & GFX_CAN_RANDOM) && gfx_scaleh > 1) {
415 			gfx_scaleh *= yscale;
416 			height = MakeAspectTable( skip, render.src.height, gfx_scaleh, yscale );
417 		} else {
418 			gfx_flags &= ~GFX_CAN_RANDOM;		//Hardware surface when possible
419 			height = MakeAspectTable( skip, render.src.height, yscale, yscale);
420 		}
421 	}
422 /* Setup the scaler variables */
423 	gfx_flags=GFX_SetSize(width,height,gfx_flags,gfx_scalew,gfx_scaleh,&RENDER_CallBack);
424 	if (gfx_flags & GFX_CAN_8)
425 		render.scale.outMode = scalerMode8;
426 	else if (gfx_flags & GFX_CAN_15)
427 		render.scale.outMode = scalerMode15;
428 	else if (gfx_flags & GFX_CAN_16)
429 		render.scale.outMode = scalerMode16;
430 	else if (gfx_flags & GFX_CAN_32)
431 		render.scale.outMode = scalerMode32;
432 	else
433 		E_Exit("Failed to create a rendering output");
434 	ScalerLineBlock_t *lineBlock;
435 	if (gfx_flags & GFX_HARDWARE) {
436 #if RENDER_USE_ADVANCED_SCALERS>1
437 		if (complexBlock) {
438 			lineBlock = &ScalerCache;
439 			render.scale.complexHandler = complexBlock->Linear[ render.scale.outMode ];
440 		} else
441 #endif
442 		{
443 			render.scale.complexHandler = 0;
444 			lineBlock = &simpleBlock->Linear;
445 		}
446 	} else {
447 #if RENDER_USE_ADVANCED_SCALERS>1
448 		if (complexBlock) {
449 			lineBlock = &ScalerCache;
450 			render.scale.complexHandler = complexBlock->Random[ render.scale.outMode ];
451 		} else
452 #endif
453 		{
454 			render.scale.complexHandler = 0;
455 			lineBlock = &simpleBlock->Random;
456 		}
457 	}
458 	switch (render.src.bpp) {
459 	case 8:
460 		render.scale.lineHandler = (*lineBlock)[0][render.scale.outMode];
461 		render.scale.linePalHandler = (*lineBlock)[4][render.scale.outMode];
462 		render.scale.inMode = scalerMode8;
463 		render.scale.cachePitch = render.src.width * 1;
464 		break;
465 	case 15:
466 		render.scale.lineHandler = (*lineBlock)[1][render.scale.outMode];
467 		render.scale.linePalHandler = 0;
468 		render.scale.inMode = scalerMode15;
469 		render.scale.cachePitch = render.src.width * 2;
470 		break;
471 	case 16:
472 		render.scale.lineHandler = (*lineBlock)[2][render.scale.outMode];
473 		render.scale.linePalHandler = 0;
474 		render.scale.inMode = scalerMode16;
475 		render.scale.cachePitch = render.src.width * 2;
476 		break;
477 	case 32:
478 		render.scale.lineHandler = (*lineBlock)[3][render.scale.outMode];
479 		render.scale.linePalHandler = 0;
480 		render.scale.inMode = scalerMode32;
481 		render.scale.cachePitch = render.src.width * 4;
482 		break;
483 	default:
484 		E_Exit("RENDER:Wrong source bpp %d", render.src.bpp );
485 	}
486 	render.scale.blocks = render.src.width / SCALER_BLOCKSIZE;
487 	render.scale.lastBlock = render.src.width % SCALER_BLOCKSIZE;
488 	render.scale.inHeight = render.src.height;
489 	/* Reset the palette change detection to it's initial value */
490 	render.pal.first= 0;
491 	render.pal.last = 255;
492 	render.pal.changed = false;
493 	memset(render.pal.modified, 0, sizeof(render.pal.modified));
494 	//Finish this frame using a copy only handler
495 	RENDER_DrawLine = RENDER_FinishLineHandler;
496 	render.scale.outWrite = 0;
497 	/* Signal the next frame to first reinit the cache */
498 	render.scale.clearCache = true;
499 	render.active=true;
500 }
501 
RENDER_CallBack(GFX_CallBackFunctions_t function)502 static void RENDER_CallBack( GFX_CallBackFunctions_t function ) {
503 	if (function == GFX_CallBackStop) {
504 		RENDER_Halt( );
505 		return;
506 	} else if (function == GFX_CallBackRedraw) {
507 		render.scale.clearCache = true;
508 		return;
509 	} else if ( function == GFX_CallBackReset) {
510 		GFX_EndUpdate( 0 );
511 		RENDER_Reset();
512 	} else {
513 		E_Exit("Unhandled GFX_CallBackReset %d", function );
514 	}
515 }
516 
RENDER_SetSize(Bitu width,Bitu height,Bitu bpp,float fps,double ratio,bool dblw,bool dblh)517 void RENDER_SetSize(Bitu width,Bitu height,Bitu bpp,float fps,double ratio,bool dblw,bool dblh) {
518 	RENDER_Halt( );
519 	if (!width || !height || width > SCALER_MAXWIDTH || height > SCALER_MAXHEIGHT) {
520 		return;
521 	}
522 	if ( ratio > 1 ) {
523 		double target = height * ratio + 0.025;
524 		ratio = target / height;
525 	} else {
526 		//This would alter the width of the screen, we don't care about rounding errors here
527 	}
528 	render.src.width=width;
529 	render.src.height=height;
530 	render.src.bpp=bpp;
531 	render.src.dblw=dblw;
532 	render.src.dblh=dblh;
533 	render.src.fps=fps;
534 	render.src.ratio=ratio;
535 	RENDER_Reset( );
536 }
537 
538 extern void GFX_SetTitle(Bit32s cycles, Bits frameskip,bool paused);
IncreaseFrameSkip(bool pressed)539 static void IncreaseFrameSkip(bool pressed) {
540 	if (!pressed)
541 		return;
542 	if (render.frameskip.max<10) render.frameskip.max++;
543 	LOG_MSG("Frame Skip at %d",render.frameskip.max);
544 	GFX_SetTitle(-1,render.frameskip.max,false);
545 }
546 
DecreaseFrameSkip(bool pressed)547 static void DecreaseFrameSkip(bool pressed) {
548 	if (!pressed)
549 		return;
550 	if (render.frameskip.max>0) render.frameskip.max--;
551 	LOG_MSG("Frame Skip at %d",render.frameskip.max);
552 	GFX_SetTitle(-1,render.frameskip.max,false);
553 }
554 /* Disabled as I don't want to waste a keybind for that. Might be used in the future (Qbix)
555 static void ChangeScaler(bool pressed) {
556 	if (!pressed)
557 		return;
558 	render.scale.op = (scalerOperation)((int)render.scale.op+1);
559 	if((render.scale.op) >= scalerLast || render.scale.size == 1) {
560 		render.scale.op = (scalerOperation)0;
561 		if(++render.scale.size > 3)
562 			render.scale.size = 1;
563 	}
564 	RENDER_CallBack( GFX_CallBackReset );
565 } */
566 
RENDER_Init(Section * sec)567 void RENDER_Init(Section * sec) {
568 	Section_prop * section=static_cast<Section_prop *>(sec);
569 
570 	//For restarting the renderer.
571 	static bool running = false;
572 	bool aspect = render.aspect;
573 	Bitu scalersize = render.scale.size;
574 	bool scalerforced = render.scale.forced;
575 	scalerOperation_t scaleOp = render.scale.op;
576 
577 	render.pal.first=256;
578 	render.pal.last=0;
579 	render.aspect=section->Get_bool("aspect");
580 	render.frameskip.max=section->Get_int("frameskip");
581 	render.frameskip.count=0;
582 	std::string cline;
583 	std::string scaler;
584 	//Check for commandline paramters and parse them through the configclass so they get checked against allowed values
585 	if (control->cmdline->FindString("-scaler",cline,false)) {
586 		section->HandleInputline(std::string("scaler=") + cline);
587 	} else if (control->cmdline->FindString("-forcescaler",cline,false)) {
588 		section->HandleInputline(std::string("scaler=") + cline + " forced");
589 	}
590 
591 	Prop_multival* prop = section->Get_multival("scaler");
592 	scaler = prop->GetSection()->Get_string("type");
593 	std::string f = prop->GetSection()->Get_string("force");
594 	render.scale.forced = false;
595 	if(f == "forced") render.scale.forced = true;
596 
597 	if (scaler == "none") { render.scale.op = scalerOpNormal;render.scale.size = 1; }
598 	else if (scaler == "normal2x") { render.scale.op = scalerOpNormal;render.scale.size = 2; }
599 	else if (scaler == "normal3x") { render.scale.op = scalerOpNormal;render.scale.size = 3; }
600 #if RENDER_USE_ADVANCED_SCALERS>2
601 	else if (scaler == "advmame2x") { render.scale.op = scalerOpAdvMame;render.scale.size = 2; }
602 	else if (scaler == "advmame3x") { render.scale.op = scalerOpAdvMame;render.scale.size = 3; }
603 	else if (scaler == "advinterp2x") { render.scale.op = scalerOpAdvInterp;render.scale.size = 2; }
604 	else if (scaler == "advinterp3x") { render.scale.op = scalerOpAdvInterp;render.scale.size = 3; }
605 	else if (scaler == "hq2x") { render.scale.op = scalerOpHQ;render.scale.size = 2; }
606 	else if (scaler == "hq3x") { render.scale.op = scalerOpHQ;render.scale.size = 3; }
607 	else if (scaler == "2xsai") { render.scale.op = scalerOpSaI;render.scale.size = 2; }
608 	else if (scaler == "super2xsai") { render.scale.op = scalerOpSuperSaI;render.scale.size = 2; }
609 	else if (scaler == "supereagle") { render.scale.op = scalerOpSuperEagle;render.scale.size = 2; }
610 #endif
611 #if RENDER_USE_ADVANCED_SCALERS>0
612 	else if (scaler == "tv2x") { render.scale.op = scalerOpTV;render.scale.size = 2; }
613 	else if (scaler == "tv3x") { render.scale.op = scalerOpTV;render.scale.size = 3; }
614 	else if (scaler == "rgb2x"){ render.scale.op = scalerOpRGB;render.scale.size = 2; }
615 	else if (scaler == "rgb3x"){ render.scale.op = scalerOpRGB;render.scale.size = 3; }
616 	else if (scaler == "scan2x"){ render.scale.op = scalerOpScan;render.scale.size = 2; }
617 	else if (scaler == "scan3x"){ render.scale.op = scalerOpScan;render.scale.size = 3; }
618 #endif
619 
620 	//If something changed that needs a ReInit
621 	// Only ReInit when there is a src.bpp (fixes crashes on startup and directly changing the scaler without a screen specified yet)
622 	if(running && render.src.bpp && ((render.aspect != aspect) || (render.scale.op != scaleOp) ||
623 				  (render.scale.size != scalersize) || (render.scale.forced != scalerforced) ||
624 				   render.scale.forced))
625 		RENDER_CallBack( GFX_CallBackReset );
626 
627 	if(!running) render.updating=true;
628 	running = true;
629 
630 	MAPPER_AddHandler(DecreaseFrameSkip,MK_f7,MMOD1,"decfskip","Dec Fskip");
631 	MAPPER_AddHandler(IncreaseFrameSkip,MK_f8,MMOD1,"incfskip","Inc Fskip");
632 	GFX_SetTitle(-1,render.frameskip.max,false);
633 }
634 
635