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: vga_draw.cpp,v 1.112 2009-11-03 21:06:59 h-a-l-9000 Exp $ */
20 
21 #include <string.h>
22 #include <math.h>
23 #include "dosbox.h"
24 #include "video.h"
25 #include "render.h"
26 #include "../gui/render_scalers.h"
27 #include "vga.h"
28 #include "pic.h"
29 
30 //#undef C_DEBUG
31 //#define C_DEBUG 1
32 //#define LOG(X,Y) LOG_MSG
33 
34 #define VGA_PARTS 4
35 
36 typedef Bit8u * (* VGA_Line_Handler)(Bitu vidstart, Bitu line);
37 
38 static VGA_Line_Handler VGA_DrawLine;
39 static Bit8u TempLine[SCALER_MAXWIDTH * 4];
40 
VGA_Draw_1BPP_Line(Bitu vidstart,Bitu line)41 static Bit8u * VGA_Draw_1BPP_Line(Bitu vidstart, Bitu line) {
42 	const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
43 	Bit32u *draw = (Bit32u *)TempLine;
44 	for (Bitu x=vga.draw.blocks;x>0;x--, vidstart++) {
45 		Bitu val = base[(vidstart & (8 * 1024 -1))];
46 		*draw++=CGA_2_Table[val >> 4];
47 		*draw++=CGA_2_Table[val & 0xf];
48 	}
49 	return TempLine;
50 }
51 
VGA_Draw_2BPP_Line(Bitu vidstart,Bitu line)52 static Bit8u * VGA_Draw_2BPP_Line(Bitu vidstart, Bitu line) {
53 	const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
54 	Bit32u * draw=(Bit32u *)TempLine;
55 	for (Bitu x=0;x<vga.draw.blocks;x++) {
56 		Bitu val = base[vidstart & vga.tandy.addr_mask];
57 		vidstart++;
58 		*draw++=CGA_4_Table[val];
59 	}
60 	return TempLine;
61 }
62 
VGA_Draw_2BPPHiRes_Line(Bitu vidstart,Bitu line)63 static Bit8u * VGA_Draw_2BPPHiRes_Line(Bitu vidstart, Bitu line) {
64 	const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
65 	Bit32u * draw=(Bit32u *)TempLine;
66 	for (Bitu x=0;x<vga.draw.blocks;x++) {
67 		Bitu val1 = base[vidstart & vga.tandy.addr_mask];
68 		++vidstart;
69 		Bitu val2 = base[vidstart & vga.tandy.addr_mask];
70 		++vidstart;
71 		*draw++=CGA_4_HiRes_Table[(val1>>4)|(val2&0xf0)];
72 		*draw++=CGA_4_HiRes_Table[(val1&0x0f)|((val2&0x0f)<<4)];
73 	}
74 	return TempLine;
75 }
76 
77 static Bitu temp[643]={0};
78 
VGA_Draw_CGA16_Line(Bitu vidstart,Bitu line)79 static Bit8u * VGA_Draw_CGA16_Line(Bitu vidstart, Bitu line) {
80 	const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
81 	const Bit8u *reader = base + vidstart;
82 	Bit32u * draw=(Bit32u *)TempLine;
83 	//Generate a temporary bitline to calculate the avarage
84 	//over bit-2  bit-1  bit  bit+1.
85 	//Combine this number with the current colour to get
86 	//an unigue index in the pallete. Or it with bit 7 as they are stored
87 	//in the upperpart to keep them from interfering the regular cga stuff
88 
89 	for(Bitu x = 0; x < 640; x++)
90 		temp[x+2] = (( reader[(x>>3)] >> (7-(x&7)) )&1) << 4;
91 		//shift 4 as that is for the index.
92 	Bitu i = 0,temp1,temp2,temp3,temp4;
93 	for (Bitu x=0;x<vga.draw.blocks;x++) {
94 		Bitu val1 = *reader++;
95 		Bitu val2 = val1&0xf;
96 		val1 >>= 4;
97 
98 		temp1 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
99 		temp2 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
100 		temp3 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
101 		temp4 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
102 
103 		*draw++ = 0x80808080|(temp1|val1) |
104 		          ((temp2|val1) << 8) |
105 		          ((temp3|val1) <<16) |
106 		          ((temp4|val1) <<24);
107 		temp1 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
108 		temp2 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
109 		temp3 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
110 		temp4 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++;
111 		*draw++ = 0x80808080|(temp1|val2) |
112 		          ((temp2|val2) << 8) |
113 		          ((temp3|val2) <<16) |
114 		          ((temp4|val2) <<24);
115 	}
116 	return TempLine;
117 }
118 
VGA_Draw_4BPP_Line(Bitu vidstart,Bitu line)119 static Bit8u * VGA_Draw_4BPP_Line(Bitu vidstart, Bitu line) {
120 	const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
121 	Bit32u * draw=(Bit32u *)TempLine;
122 	for (Bitu x=0;x<vga.draw.blocks;x++) {
123 		Bitu val1 = base[vidstart & vga.tandy.addr_mask];
124 		++vidstart;
125 		Bitu val2 = base[vidstart & vga.tandy.addr_mask];
126 		++vidstart;
127 		*draw++=(val1 & 0x0f) << 8  |
128 				(val1 & 0xf0) >> 4  |
129 				(val2 & 0x0f) << 24 |
130 				(val2 & 0xf0) << 12;
131 	}
132 	return TempLine;
133 }
134 
VGA_Draw_4BPP_Line_Double(Bitu vidstart,Bitu line)135 static Bit8u * VGA_Draw_4BPP_Line_Double(Bitu vidstart, Bitu line) {
136 	const Bit8u *base = vga.tandy.draw_base + ((line & vga.tandy.line_mask) << vga.tandy.line_shift);
137 	Bit32u * draw=(Bit32u *)TempLine;
138 	for (Bitu x=0;x<vga.draw.blocks;x++) {
139 		Bitu val = base[vidstart & vga.tandy.addr_mask];
140 		++vidstart;
141 		*draw++=(val & 0xf0) >> 4  |
142 				(val & 0xf0) << 4  |
143 				(val & 0x0f) << 16 |
144 				(val & 0x0f) << 24;
145 	}
146 	return TempLine;
147 }
148 
149 #ifdef VGA_KEEP_CHANGES
VGA_Draw_Changes_Line(Bitu vidstart,Bitu line)150 static Bit8u * VGA_Draw_Changes_Line(Bitu vidstart, Bitu line) {
151 	Bitu checkMask = vga.changes.checkMask;
152 	Bit8u *map = vga.changes.map;
153 	Bitu start = (vidstart >> VGA_CHANGE_SHIFT);
154 	Bitu end = ((vidstart + vga.draw.line_length ) >> VGA_CHANGE_SHIFT);
155 	for (; start <= end;start++) {
156 		if ( map[start] & checkMask ) {
157 			Bitu offset = vidstart & vga.draw.linear_mask;
158 			if(vga.draw.linear_mask-offset < vga.draw.line_length)
159 				memcpy(vga.draw.linear_base+vga.draw.linear_mask+1, vga.draw.linear_base, vga.draw.line_length);
160 			Bit8u *ret = &vga.draw.linear_base[ offset ];
161 #if !defined(C_UNALIGNED_MEMORY)
162 			if (GCC_UNLIKELY( ((Bitu)ret) & (sizeof(Bitu)-1)) ) {
163 				memcpy( TempLine, ret, vga.draw.line_length );
164 				return TempLine;
165 			}
166 #endif
167 			return ret;
168 		}
169 	}
170 //	memset( TempLine, 0x30, vga.changes.lineWidth );
171 //	return TempLine;
172 	return 0;
173 }
174 
175 #endif
176 
VGA_Draw_Linear_Line(Bitu vidstart,Bitu)177 static Bit8u * VGA_Draw_Linear_Line(Bitu vidstart, Bitu /*line*/) {
178 // There is guaranteed extra memory past the wrap boundary. So, instead of using temporary
179 // storage just copy appropriate chunk from the beginning to the wrap boundary when needed.
180 	Bitu offset = vidstart & vga.draw.linear_mask;
181 	if (vga.draw.linear_mask-offset < vga.draw.line_length)
182 		memcpy(vga.draw.linear_base+vga.draw.linear_mask+1, vga.draw.linear_base, vga.draw.line_length);
183 	Bit8u *ret = &vga.draw.linear_base[ offset ];
184 #if !defined(C_UNALIGNED_MEMORY)
185 	if (GCC_UNLIKELY( ((Bitu)ret) & (sizeof(Bitu)-1)) ) {
186 		memcpy( TempLine, ret, vga.draw.line_length );
187 		return TempLine;
188 	}
189 #endif
190 	return ret;
191 }
192 
VGA_Draw_Xlat16_Linear_Line(Bitu vidstart,Bitu)193 static Bit8u * VGA_Draw_Xlat16_Linear_Line(Bitu vidstart, Bitu /*line*/) {
194 	Bit8u *ret = &vga.draw.linear_base[ vidstart & vga.draw.linear_mask ];
195 	Bit16u* temps = (Bit16u*) TempLine;
196 	for(Bitu i = 0; i < vga.draw.line_length; i++) {
197 		temps[i]=vga.dac.xlat16[ret[i]];
198 	}
199 	return TempLine;
200 	/*
201 #if !defined(C_UNALIGNED_MEMORY)
202 	if (GCC_UNLIKELY( ((Bitu)ret) & (sizeof(Bitu)-1)) ) {
203 		memcpy( TempLine, ret, vga.draw.line_length );
204 		return TempLine;
205 	}
206 #endif
207 	return ret;*/
208 }
209 
210 //Test version, might as well keep it
211 /* static Bit8u * VGA_Draw_Chain_Line(Bitu vidstart, Bitu line) {
212 	Bitu i = 0;
213 	for ( i = 0; i < vga.draw.width;i++ ) {
214 		Bitu addr = vidstart + i;
215 		TempLine[i] = vga.mem.linear[((addr&~3)<<2)+(addr&3)];
216 	}
217 	return TempLine;
218 } */
219 
VGA_Draw_VGA_Line_HWMouse(Bitu vidstart,Bitu)220 static Bit8u * VGA_Draw_VGA_Line_HWMouse( Bitu vidstart, Bitu /*line*/) {
221 	if (!svga.hardware_cursor_active || !svga.hardware_cursor_active())
222 		// HW Mouse not enabled, use the tried and true call
223 		return &vga.mem.linear[vidstart];
224 
225 	Bitu lineat = (vidstart-(vga.config.real_start<<2)) / vga.draw.width;
226 	if ((vga.s3.hgc.posx >= vga.draw.width) ||
227 		(lineat < vga.s3.hgc.originy) ||
228 		(lineat > (vga.s3.hgc.originy + (63U-vga.s3.hgc.posy))) ) {
229 		// the mouse cursor *pattern* is not on this line
230 		return &vga.mem.linear[ vidstart ];
231 	} else {
232 		// Draw mouse cursor: cursor is a 64x64 pattern which is shifted (inside the
233 		// 64x64 mouse cursor space) to the right by posx pixels and up by posy pixels.
234 		// This is used when the mouse cursor partially leaves the screen.
235 		// It is arranged as bitmap of 16bits of bitA followed by 16bits of bitB, each
236 		// AB bits corresponding to a cursor pixel. The whole map is 8kB in size.
237 		memcpy(TempLine, &vga.mem.linear[ vidstart ], vga.draw.width);
238 		// the index of the bit inside the cursor bitmap we start at:
239 		Bitu sourceStartBit = ((lineat - vga.s3.hgc.originy) + vga.s3.hgc.posy)*64 + vga.s3.hgc.posx;
240 		// convert to video memory addr and bit index
241 		// start adjusted to the pattern structure (thus shift address by 2 instead of 3)
242 		// Need to get rid of the third bit, so "/8 *2" becomes ">> 2 & ~1"
243 		Bitu cursorMemStart = ((sourceStartBit >> 2)& ~1) + (((Bit32u)vga.s3.hgc.startaddr) << 10);
244 		Bitu cursorStartBit = sourceStartBit & 0x7;
245 		// stay at the right position in the pattern
246 		if (cursorMemStart & 0x2) cursorMemStart--;
247 		Bitu cursorMemEnd = cursorMemStart + ((64-vga.s3.hgc.posx) >> 2);
248 		Bit8u* xat = &TempLine[vga.s3.hgc.originx]; // mouse data start pos. in scanline
249 		for (Bitu m = cursorMemStart; m < cursorMemEnd; (m&1)?(m+=3):m++) {
250 			// for each byte of cursor data
251 			Bit8u bitsA = vga.mem.linear[m];
252 			Bit8u bitsB = vga.mem.linear[m+2];
253 			for (Bit8u bit=(0x80 >> cursorStartBit); bit != 0; bit >>= 1) {
254 				// for each bit
255 				cursorStartBit=0; // only the first byte has some bits cut off
256 				if (bitsA&bit) {
257 					if (bitsB&bit) *xat ^= 0xFF; // Invert screen data
258 					//else Transparent
259 				} else if (bitsB&bit) {
260 					*xat = vga.s3.hgc.forestack[0]; // foreground color
261 				} else {
262 					*xat = vga.s3.hgc.backstack[0];
263 				}
264 				xat++;
265 			}
266 		}
267 		return TempLine;
268 	}
269 }
270 
VGA_Draw_LIN16_Line_HWMouse(Bitu vidstart,Bitu)271 static Bit8u * VGA_Draw_LIN16_Line_HWMouse(Bitu vidstart, Bitu /*line*/) {
272 	if (!svga.hardware_cursor_active || !svga.hardware_cursor_active())
273 		return &vga.mem.linear[vidstart];
274 
275 	Bitu lineat = ((vidstart-(vga.config.real_start<<2)) >> 1) / vga.draw.width;
276 	if ((vga.s3.hgc.posx >= vga.draw.width) ||
277 		(lineat < vga.s3.hgc.originy) ||
278 		(lineat > (vga.s3.hgc.originy + (63U-vga.s3.hgc.posy))) ) {
279 		return &vga.mem.linear[vidstart];
280 	} else {
281 		memcpy(TempLine, &vga.mem.linear[ vidstart ], vga.draw.width*2);
282 		Bitu sourceStartBit = ((lineat - vga.s3.hgc.originy) + vga.s3.hgc.posy)*64 + vga.s3.hgc.posx;
283  		Bitu cursorMemStart = ((sourceStartBit >> 2)& ~1) + (((Bit32u)vga.s3.hgc.startaddr) << 10);
284 		Bitu cursorStartBit = sourceStartBit & 0x7;
285 		if (cursorMemStart & 0x2) cursorMemStart--;
286 		Bitu cursorMemEnd = cursorMemStart + ((64-vga.s3.hgc.posx) >> 2);
287 		Bit16u* xat = &((Bit16u*)TempLine)[vga.s3.hgc.originx];
288 		for (Bitu m = cursorMemStart; m < cursorMemEnd; (m&1)?(m+=3):m++) {
289 			// for each byte of cursor data
290 			Bit8u bitsA = vga.mem.linear[m];
291 			Bit8u bitsB = vga.mem.linear[m+2];
292 			for (Bit8u bit=(0x80 >> cursorStartBit); bit != 0; bit >>= 1) {
293 				// for each bit
294 				cursorStartBit=0;
295 				if (bitsA&bit) {
296 					// byte order doesn't matter here as all bits get flipped
297 					if (bitsB&bit) *xat ^= ~0U;
298 					//else Transparent
299 				} else if (bitsB&bit) {
300 					// Source as well as destination are Bit8u arrays,
301 					// so this should work out endian-wise?
302 					*xat = *(Bit16u*)vga.s3.hgc.forestack;
303 				} else {
304 					*xat = *(Bit16u*)vga.s3.hgc.backstack;
305 				}
306 				xat++;
307 			}
308 		}
309 		return TempLine;
310 	}
311 }
312 
VGA_Draw_LIN32_Line_HWMouse(Bitu vidstart,Bitu)313 static Bit8u * VGA_Draw_LIN32_Line_HWMouse(Bitu vidstart, Bitu /*line*/) {
314 	if (!svga.hardware_cursor_active || !svga.hardware_cursor_active())
315 		return &vga.mem.linear[vidstart];
316 
317 	Bitu lineat = ((vidstart-(vga.config.real_start<<2)) >> 2) / vga.draw.width;
318 	if ((vga.s3.hgc.posx >= vga.draw.width) ||
319 		(lineat < vga.s3.hgc.originy) ||
320 		(lineat > (vga.s3.hgc.originy + (63U-vga.s3.hgc.posy))) ) {
321 		return &vga.mem.linear[ vidstart ];
322 	} else {
323 		memcpy(TempLine, &vga.mem.linear[ vidstart ], vga.draw.width*4);
324 		Bitu sourceStartBit = ((lineat - vga.s3.hgc.originy) + vga.s3.hgc.posy)*64 + vga.s3.hgc.posx;
325 		Bitu cursorMemStart = ((sourceStartBit >> 2)& ~1) + (((Bit32u)vga.s3.hgc.startaddr) << 10);
326 		Bitu cursorStartBit = sourceStartBit & 0x7;
327 		if (cursorMemStart & 0x2) cursorMemStart--;
328 		Bitu cursorMemEnd = cursorMemStart + ((64-vga.s3.hgc.posx) >> 2);
329 		Bit32u* xat = &((Bit32u*)TempLine)[vga.s3.hgc.originx];
330 		for (Bitu m = cursorMemStart; m < cursorMemEnd; (m&1)?(m+=3):m++) {
331 			// for each byte of cursor data
332 			Bit8u bitsA = vga.mem.linear[m];
333 			Bit8u bitsB = vga.mem.linear[m+2];
334 			for (Bit8u bit=(0x80 >> cursorStartBit); bit != 0; bit >>= 1) { // for each bit
335 				cursorStartBit=0;
336 				if (bitsA&bit) {
337 					if (bitsB&bit) *xat ^= ~0U;
338 					//else Transparent
339 				} else if (bitsB&bit) {
340 					*xat = *(Bit32u*)vga.s3.hgc.forestack;
341 				} else {
342 					*xat = *(Bit32u*)vga.s3.hgc.backstack;
343 				}
344 				xat++;
345 			}
346 		}
347 		return TempLine;
348 	}
349 }
350 
VGA_Text_Memwrap(Bitu vidstart)351 static const Bit8u* VGA_Text_Memwrap(Bitu vidstart) {
352 	vidstart &= vga.draw.linear_mask;
353 	Bitu line_end = 2 * vga.draw.blocks;
354 	if (GCC_UNLIKELY((vidstart + line_end) > vga.draw.linear_mask)) {
355 		// wrapping in this line
356 		Bitu break_pos = (vga.draw.linear_mask - vidstart) + 1;
357 		// need a temporary storage - TempLine/2 is ok for a bit more than 132 columns
358 		memcpy(&TempLine[sizeof(TempLine)/2], &vga.tandy.draw_base[vidstart], break_pos);
359 		memcpy(&TempLine[sizeof(TempLine)/2 + break_pos],&vga.tandy.draw_base[0], line_end - break_pos);
360 		return &TempLine[sizeof(TempLine)/2];
361 	} else return &vga.tandy.draw_base[vidstart];
362 }
363 
364 static Bit32u FontMask[2]={0xffffffff,0x0};
VGA_TEXT_Draw_Line(Bitu vidstart,Bitu line)365 static Bit8u * VGA_TEXT_Draw_Line(Bitu vidstart, Bitu line) {
366 	Bits font_addr;
367 	Bit32u * draw=(Bit32u *)TempLine;
368 	const Bit8u* vidmem = VGA_Text_Memwrap(vidstart);
369 	for (Bitu cx=0;cx<vga.draw.blocks;cx++) {
370 		Bitu chr=vidmem[cx*2];
371 		Bitu col=vidmem[cx*2+1];
372 		Bitu font=vga.draw.font_tables[(col >> 3)&1][chr*32+line];
373 		Bit32u mask1=TXT_Font_Table[font>>4] & FontMask[col >> 7];
374 		Bit32u mask2=TXT_Font_Table[font&0xf] & FontMask[col >> 7];
375 		Bit32u fg=TXT_FG_Table[col&0xf];
376 		Bit32u bg=TXT_BG_Table[col>>4];
377 		*draw++=(fg&mask1) | (bg&~mask1);
378 		*draw++=(fg&mask2) | (bg&~mask2);
379 	}
380 	if (!vga.draw.cursor.enabled || !(vga.draw.cursor.count&0x8)) goto skip_cursor;
381 	font_addr = (vga.draw.cursor.address-vidstart) >> 1;
382 	if (font_addr>=0 && font_addr<(Bits)vga.draw.blocks) {
383 		if (line<vga.draw.cursor.sline) goto skip_cursor;
384 		if (line>vga.draw.cursor.eline) goto skip_cursor;
385 		draw=(Bit32u *)&TempLine[font_addr*8];
386 		Bit32u att=TXT_FG_Table[vga.tandy.draw_base[vga.draw.cursor.address+1]&0xf];
387 		*draw++=att;*draw++=att;
388 	}
389 skip_cursor:
390 	return TempLine;
391 }
392 
VGA_TEXT_Herc_Draw_Line(Bitu vidstart,Bitu line)393 static Bit8u * VGA_TEXT_Herc_Draw_Line(Bitu vidstart, Bitu line) {
394 	Bits font_addr;
395 	Bit32u * draw=(Bit32u *)TempLine;
396 	const Bit8u* vidmem = VGA_Text_Memwrap(vidstart);
397 
398 	for (Bitu cx=0;cx<vga.draw.blocks;cx++) {
399 		Bitu chr=vidmem[cx*2];
400 		Bitu attrib=vidmem[cx*2+1];
401 		if (!(attrib&0x77)) {
402 			// 00h, 80h, 08h, 88h produce black space
403 			*draw++=0;
404 			*draw++=0;
405 		} else {
406 			Bit32u bg, fg;
407 			bool underline=false;
408 			if ((attrib&0x77)==0x70) {
409 				bg = TXT_BG_Table[0x7];
410 				if (attrib&0x8) fg = TXT_FG_Table[0xf];
411 				else fg = TXT_FG_Table[0x0];
412 			} else {
413 				if (((Bitu)(vga.crtc.underline_location&0x1f)==line) && ((attrib&0x77)==0x1)) underline=true;
414 				bg = TXT_BG_Table[0x0];
415 				if (attrib&0x8) fg = TXT_FG_Table[0xf];
416 				else fg = TXT_FG_Table[0x7];
417 			}
418 			Bit32u mask1, mask2;
419 			if (GCC_UNLIKELY(underline)) mask1 = mask2 = FontMask[attrib >> 7];
420 			else {
421 				Bitu font=vga.draw.font_tables[0][chr*32+line];
422 				mask1=TXT_Font_Table[font>>4] & FontMask[attrib >> 7]; // blinking
423 				mask2=TXT_Font_Table[font&0xf] & FontMask[attrib >> 7];
424 			}
425 			*draw++=(fg&mask1) | (bg&~mask1);
426 			*draw++=(fg&mask2) | (bg&~mask2);
427 		}
428 	}
429 	if (!vga.draw.cursor.enabled || !(vga.draw.cursor.count&0x8)) goto skip_cursor;
430 	font_addr = (vga.draw.cursor.address-vidstart) >> 1;
431 	if (font_addr>=0 && font_addr<(Bits)vga.draw.blocks) {
432 		if (line<vga.draw.cursor.sline) goto skip_cursor;
433 		if (line>vga.draw.cursor.eline) goto skip_cursor;
434 		draw=(Bit32u *)&TempLine[font_addr*8];
435 		Bit8u attr = vga.tandy.draw_base[vga.draw.cursor.address+1];
436 		Bit32u cg;
437 		if (attr&0x8) {
438 			cg = TXT_FG_Table[0xf];
439 		} else if ((attr&0x77)==0x70) {
440 			cg = TXT_FG_Table[0x0];
441 		} else {
442 			cg = TXT_FG_Table[0x7];
443 		}
444 		*draw++=cg;*draw++=cg;
445 	}
446 skip_cursor:
447 	return TempLine;
448 }
449 
VGA_TEXT_Xlat16_Draw_Line(Bitu vidstart,Bitu line)450 static Bit8u * VGA_TEXT_Xlat16_Draw_Line(Bitu vidstart, Bitu line) {
451 	Bits font_addr;
452 	Bit16u * draw=(Bit16u *)TempLine;
453 	const Bit8u* vidmem = VGA_Text_Memwrap(vidstart);
454 	for (Bitu cx=0;cx<vga.draw.blocks;cx++) {
455 		Bitu chr=vidmem[cx*2];
456 		Bitu col=vidmem[cx*2+1];
457 		Bitu font=vga.draw.font_tables[(col >> 3)&1][chr*32+line];
458 		Bit32u mask1=TXT_Font_Table[font>>4] & FontMask[col >> 7];
459 		Bit32u mask2=TXT_Font_Table[font&0xf] & FontMask[col >> 7];
460 		Bit32u fg=TXT_FG_Table[col&0xf];
461 		Bit32u bg=TXT_BG_Table[col>>4];
462 
463 		mask1=(fg&mask1) | (bg&~mask1);
464 		mask2=(fg&mask2) | (bg&~mask2);
465 
466 		for(int i = 0; i < 4; i++) {
467 			*draw++ = vga.dac.xlat16[(mask1>>8*i)&0xff];
468 		}
469 		for(int i = 0; i < 4; i++) {
470 			*draw++ = vga.dac.xlat16[(mask2>>8*i)&0xff];
471 		}
472 	}
473 	if (!vga.draw.cursor.enabled || !(vga.draw.cursor.count&0x8)) goto skip_cursor;
474 	font_addr = (vga.draw.cursor.address-vidstart) >> 1;
475 	if (font_addr>=0 && font_addr<(Bits)vga.draw.blocks) {
476 		if (line<vga.draw.cursor.sline) goto skip_cursor;
477 		if (line>vga.draw.cursor.eline) goto skip_cursor;
478 		draw=(Bit16u *)&TempLine[font_addr*16];
479 		Bit8u att=(Bit8u)(TXT_FG_Table[vga.tandy.draw_base[vga.draw.cursor.address+1]&0xf]&0xff);
480 		for(int i = 0; i < 8; i++) {
481 			*draw++ = vga.dac.xlat16[att];
482 		}
483 	}
484 skip_cursor:
485 	return TempLine;
486 }
487 
488 /*
489 static Bit8u * VGA_TEXT_Draw_Line_9(Bitu vidstart, Bitu line) {
490 	Bits font_addr;
491 	Bit8u * draw=(Bit8u *)TempLine;
492 	bool underline=(Bitu)(vga.crtc.underline_location&0x1f)==line;
493 	Bit8u pel_pan=(Bit8u)vga.draw.panning;
494 	if ((vga.attr.mode_control&0x20) && (vga.draw.lines_done>=vga.draw.split_line)) pel_pan=0;
495 	const Bit8u* vidmem = VGA_Text_Memwrap(vidstart);
496 	Bit8u chr=vidmem[0];
497 	Bit8u col=vidmem[1];
498 	Bit8u font=(vga.draw.font_tables[(col >> 3)&1][chr*32+line])<<pel_pan;
499 	if (underline && ((col&0x07) == 0x01)) font=0xff;
500 	Bit8u fg=col&0xf;
501 	Bit8u bg=(Bit8u)(TXT_BG_Table[col>>4]&0xff);
502 	Bitu draw_blocks=vga.draw.blocks;
503 	draw_blocks++;
504 	for (Bitu cx=1;cx<draw_blocks;cx++) {
505 		if (pel_pan) {
506 			chr=vidmem[cx*2];
507 			col=vidmem[cx*2+1];
508 			if (underline && ((col&0x07) == 0x01)) font|=0xff>>(8-pel_pan);
509 			else font|=vga.draw.font_tables[(col >> 3)&1][chr*32+line]>>(8-pel_pan);
510 			fg=col&0xf;
511 			bg=(Bit8u)(TXT_BG_Table[col>>4]&0xff);
512 		} else {
513 			chr=vidmem[(cx-1)*2];
514 			col=vidmem[(cx-1)*2+1];
515 			if (underline && ((col&0x07) == 0x01)) font=0xff;
516 			else font=vga.draw.font_tables[(col >> 3)&1][chr*32+line];
517 			fg=col&0xf;
518 			bg=(Bit8u)(TXT_BG_Table[col>>4]&0xff);
519 		}
520 		if (FontMask[col>>7]==0) font=0;
521 		*draw++=(font&0x80)?fg:bg;		*draw++=(font&0x40)?fg:bg;
522 		*draw++=(font&0x20)?fg:bg;		*draw++=(font&0x10)?fg:bg;
523 		*draw++=(font&0x08)?fg:bg;		*draw++=(font&0x04)?fg:bg;
524 		*draw++=(font&0x02)?fg:bg;
525 		Bit8u last=(font&0x01)?fg:bg;
526 		*draw++=last;
527 		*draw++=((vga.attr.mode_control&0x04) && ((chr<0xc0) || (chr>0xdf))) ? bg : last;
528 		if (pel_pan) {
529 			if (underline && ((col&0x07) == 0x01)) font=0xff;
530 			else font=(vga.draw.font_tables[(col >> 3)&1][chr*32+line])<<pel_pan;
531 		}
532 	}
533 	if (!vga.draw.cursor.enabled || !(vga.draw.cursor.count&0x8)) goto skip_cursor;
534 	font_addr = (vga.draw.cursor.address-vidstart) >> 1;
535 	if (font_addr>=0 && font_addr<(Bits)vga.draw.blocks) {
536 		if (line<vga.draw.cursor.sline) goto skip_cursor;
537 		if (line>vga.draw.cursor.eline) goto skip_cursor;
538 		draw=&TempLine[font_addr*9];
539 		Bit8u fg=vga.tandy.draw_base[vga.draw.cursor.address+1]&0xf;
540 		*draw++=fg;		*draw++=fg;		*draw++=fg;		*draw++=fg;
541 		*draw++=fg;		*draw++=fg;		*draw++=fg;		*draw++=fg;
542 	}
543 skip_cursor:
544 	return TempLine;
545 }
546 */
547 
VGA_TEXT_Xlat16_Draw_Line_9(Bitu vidstart,Bitu line)548 static Bit8u * VGA_TEXT_Xlat16_Draw_Line_9(Bitu vidstart, Bitu line) {
549 	Bits font_addr;
550 	Bit16u * draw=(Bit16u *)TempLine;
551 	bool underline=(Bitu)(vga.crtc.underline_location&0x1f)==line;
552 	Bit8u pel_pan=(Bit8u)vga.draw.panning;
553 	if ((vga.attr.mode_control&0x20) && (vga.draw.lines_done>=vga.draw.split_line)) pel_pan=0;
554 	const Bit8u* vidmem = VGA_Text_Memwrap(vidstart);
555 	Bit8u chr=vidmem[0];
556 	Bit8u col=vidmem[1];
557 	Bit8u font=(vga.draw.font_tables[(col >> 3)&1][chr*32+line])<<pel_pan;
558 	if (underline && ((col&0x07) == 0x01)) font=0xff;
559 	Bit8u fg=col&0xf;
560 	Bit8u bg=(Bit8u)(TXT_BG_Table[col>>4]&0xff);
561 	Bitu draw_blocks=vga.draw.blocks;
562 	draw_blocks++;
563 	for (Bitu cx=1;cx<draw_blocks;cx++) {
564 		if (pel_pan) {
565 			chr=vidmem[cx*2];
566 			col=vidmem[cx*2+1];
567 			if (underline && ((col&0x07) == 0x01)) font|=0xff>>(8-pel_pan);
568 			else font|=vga.draw.font_tables[(col >> 3)&1][chr*32+line]>>(8-pel_pan);
569 			fg=col&0xf;
570 			bg=(Bit8u)(TXT_BG_Table[col>>4]&0xff);
571 		} else {
572 			chr=vidmem[(cx-1)*2];
573 			col=vidmem[(cx-1)*2+1];
574 			if (underline && ((col&0x07) == 0x01)) font=0xff;
575 			else font=vga.draw.font_tables[(col >> 3)&1][chr*32+line];
576 			fg=col&0xf;
577 			bg=(Bit8u)(TXT_BG_Table[col>>4]&0xff);
578 		}
579 		if (FontMask[col>>7]==0) font=0;
580 		Bit8u mask=0x80;
581 		for (int i = 0; i < 7; i++) {
582 			*draw++=vga.dac.xlat16[font&mask?fg:bg];
583 			mask>>=1;
584 		}
585 		Bit16u lastval=vga.dac.xlat16[font&mask?fg:bg];
586 		*draw++=lastval;
587 		*draw++=(((vga.attr.mode_control&0x04) && ((chr<0xc0) || (chr>0xdf))) &&
588 			!(underline && ((col&0x07) == 0x01))) ?
589 			(vga.dac.xlat16[bg]) : lastval;
590 		if (pel_pan) {
591 			if (underline && ((col&0x07) == 0x01)) font=0xff;
592 			else font=(vga.draw.font_tables[(col >> 3)&1][chr*32+line])<<pel_pan;
593 		}
594 	}
595 	if (!vga.draw.cursor.enabled || !(vga.draw.cursor.count&0x8)) goto skip_cursor;
596 	font_addr = (vga.draw.cursor.address-vidstart) >> 1;
597 	if (font_addr>=0 && font_addr<(Bits)vga.draw.blocks) {
598 		if (line<vga.draw.cursor.sline) goto skip_cursor;
599 		if (line>vga.draw.cursor.eline) goto skip_cursor;
600 		draw=(Bit16u*)&TempLine[font_addr*18];
601 		Bit8u fg=vga.tandy.draw_base[vga.draw.cursor.address+1]&0xf;
602 		for(int i = 0; i < 8; i++) {
603 			*draw++ = vga.dac.xlat16[fg];
604 		}
605 		//if(underline && ((col&0x07) == 0x01))
606 		//	*draw = vga.dac.xlat16[fg];
607 	}
608 skip_cursor:
609 	return TempLine;
610 }
611 
612 #ifdef VGA_KEEP_CHANGES
VGA_ChangesEnd(void)613 static INLINE void VGA_ChangesEnd(void ) {
614 	if ( vga.changes.active ) {
615 //		vga.changes.active = false;
616 		Bitu end = vga.draw.address >> VGA_CHANGE_SHIFT;
617 		Bitu total = 4 + end - vga.changes.start;
618 		Bit32u clearMask = vga.changes.clearMask;
619 		total >>= 2;
620 		Bit32u *clear = (Bit32u *)&vga.changes.map[  vga.changes.start & ~3 ];
621 		while ( total-- ) {
622 			clear[0] &= clearMask;
623 			clear++;
624 		}
625 	}
626 }
627 #endif
628 
629 
VGA_ProcessSplit()630 static void VGA_ProcessSplit() {
631 	// On the EGA the address is always reset to 0.
632 	if ((vga.attr.mode_control&0x20) || (machine==MCH_EGA)) {
633 		vga.draw.address=0;
634 	} else {
635 		// In text mode only the characters are shifted by panning, not the address;
636 		// this is done in the text line draw function.
637 		vga.draw.address = vga.draw.byte_panning_shift*vga.draw.bytes_skip;
638 		if (!(vga.mode==M_TEXT)) vga.draw.address += vga.draw.panning;
639 	}
640 	vga.draw.address_line=0;
641 }
642 
VGA_DrawSingleLine(Bitu)643 static void VGA_DrawSingleLine(Bitu /*blah*/) {
644 	if (GCC_UNLIKELY(vga.attr.disabled)) {
645 		// draw blanked line (DoWhackaDo, Alien Carnage, TV sports Football)
646 		memset(TempLine, 0, sizeof(TempLine));
647 		RENDER_DrawLine(TempLine);
648 	} else {
649 		Bit8u * data=VGA_DrawLine( vga.draw.address, vga.draw.address_line );
650 		RENDER_DrawLine(data);
651 	}
652 
653 	vga.draw.address_line++;
654 	if (vga.draw.address_line>=vga.draw.address_line_total) {
655 		vga.draw.address_line=0;
656 		vga.draw.address+=vga.draw.address_add;
657 	}
658 	vga.draw.lines_done++;
659 	if (vga.draw.split_line==vga.draw.lines_done) VGA_ProcessSplit();
660 	if (vga.draw.lines_done < vga.draw.lines_total) {
661 		PIC_AddEvent(VGA_DrawSingleLine,(float)vga.draw.delay.htotal);
662 	} else RENDER_EndUpdate(false);
663 }
664 
VGA_DrawPart(Bitu lines)665 static void VGA_DrawPart(Bitu lines) {
666 	while (lines--) {
667 		Bit8u * data=VGA_DrawLine( vga.draw.address, vga.draw.address_line );
668 		RENDER_DrawLine(data);
669 		vga.draw.address_line++;
670 		if (vga.draw.address_line>=vga.draw.address_line_total) {
671 			vga.draw.address_line=0;
672 			vga.draw.address+=vga.draw.address_add;
673 		}
674 		vga.draw.lines_done++;
675 		if (vga.draw.split_line==vga.draw.lines_done) {
676 #ifdef VGA_KEEP_CHANGES
677 			VGA_ChangesEnd( );
678 #endif
679 			VGA_ProcessSplit();
680 #ifdef VGA_KEEP_CHANGES
681 			vga.changes.start = vga.draw.address >> VGA_CHANGE_SHIFT;
682 #endif
683 		}
684 	}
685 	if (--vga.draw.parts_left) {
686 		PIC_AddEvent(VGA_DrawPart,(float)vga.draw.delay.parts,
687 			 (vga.draw.parts_left!=1) ? vga.draw.parts_lines  : (vga.draw.lines_total - vga.draw.lines_done));
688 	} else {
689 #ifdef VGA_KEEP_CHANGES
690 		VGA_ChangesEnd();
691 #endif
692 		RENDER_EndUpdate(false);
693 	}
694 }
695 
VGA_SetBlinking(Bitu enabled)696 void VGA_SetBlinking(Bitu enabled) {
697 	Bitu b;
698 	LOG(LOG_VGA,LOG_NORMAL)("Blinking %d",enabled);
699 	if (enabled) {
700 		b=0;vga.draw.blinking=1; //used to -1 but blinking is unsigned
701 		vga.attr.mode_control|=0x08;
702 		vga.tandy.mode_control|=0x20;
703 	} else {
704 		b=8;vga.draw.blinking=0;
705 		vga.attr.mode_control&=~0x08;
706 		vga.tandy.mode_control&=~0x20;
707 	}
708 	for (Bitu i=0;i<8;i++) TXT_BG_Table[i+8]=(b+i) | ((b+i) << 8)| ((b+i) <<16) | ((b+i) << 24);
709 }
710 
711 #ifdef VGA_KEEP_CHANGES
VGA_ChangesStart(void)712 static void INLINE VGA_ChangesStart( void ) {
713 	vga.changes.start = vga.draw.address >> VGA_CHANGE_SHIFT;
714 	vga.changes.last = vga.changes.start;
715 	if ( vga.changes.lastAddress != vga.draw.address ) {
716 //		LOG_MSG("Address");
717 		VGA_DrawLine = VGA_Draw_Linear_Line;
718 		vga.changes.lastAddress = vga.draw.address;
719 	} else if ( render.fullFrame ) {
720 //		LOG_MSG("Full Frame");
721 		VGA_DrawLine = VGA_Draw_Linear_Line;
722 	} else {
723 //		LOG_MSG("Changes");
724 		VGA_DrawLine = VGA_Draw_Changes_Line;
725 	}
726 	vga.changes.active = true;
727 	vga.changes.checkMask = vga.changes.writeMask;
728 	vga.changes.clearMask = ~( 0x01010101 << (vga.changes.frame & 7));
729 	vga.changes.frame++;
730 	vga.changes.writeMask = 1 << (vga.changes.frame & 7);
731 }
732 #endif
733 
VGA_VertInterrupt(Bitu)734 static void VGA_VertInterrupt(Bitu /*val*/) {
735 	if ((!vga.draw.vret_triggered) && ((vga.crtc.vertical_retrace_end&0x30)==0x10)) {
736 		vga.draw.vret_triggered=true;
737 		if (GCC_UNLIKELY(machine==MCH_EGA)) PIC_ActivateIRQ(9);
738 	}
739 }
740 
VGA_Other_VertInterrupt(Bitu val)741 static void VGA_Other_VertInterrupt(Bitu val) {
742 	if (val) PIC_ActivateIRQ(5);
743 	else PIC_DeActivateIRQ(5);
744 }
745 
VGA_DisplayStartLatch(Bitu)746 static void VGA_DisplayStartLatch(Bitu /*val*/) {
747 	vga.config.real_start=vga.config.display_start & (vga.vmemwrap-1);
748 	vga.draw.bytes_skip = vga.config.bytes_skip;
749 }
750 
VGA_PanningLatch(Bitu)751 static void VGA_PanningLatch(Bitu /*val*/) {
752 	vga.draw.panning = vga.config.pel_panning;
753 }
754 
VGA_VerticalTimer(Bitu)755 static void VGA_VerticalTimer(Bitu /*val*/) {
756 	vga.draw.delay.framestart = PIC_FullIndex();
757 	PIC_AddEvent( VGA_VerticalTimer, (float)vga.draw.delay.vtotal );
758 
759 	switch(machine) {
760 	case MCH_PCJR:
761 	case MCH_TANDY:
762 		// PCJr: Vsync is directly connected to the IRQ controller
763 		// Some earlier Tandy models are said to have a vsync interrupt too
764 		PIC_AddEvent(VGA_Other_VertInterrupt, (float)vga.draw.delay.vrstart, 1);
765 		PIC_AddEvent(VGA_Other_VertInterrupt, (float)vga.draw.delay.vrend, 0);
766 		// fall-through
767 	case MCH_CGA:
768 	case MCH_HERC:
769 		// MC6845-powered graphics: Loading the display start latch happens somewhere
770 		// after vsync off and before first visible scanline, so probably here
771 		VGA_DisplayStartLatch(0);
772 		break;
773 	case MCH_VGA:
774 	case MCH_EGA:
775 		PIC_AddEvent(VGA_DisplayStartLatch, (float)vga.draw.delay.vrstart);
776 		PIC_AddEvent(VGA_PanningLatch, (float)vga.draw.delay.vrend);
777 		// EGA: 82c435 datasheet: interrupt happens at display end
778 		// VGA: checked with scope; however disabled by default by jumper on VGA boards
779 		// add a little amount of time to make sure the last drawpart has already fired
780 		PIC_AddEvent(VGA_VertInterrupt,(float)(vga.draw.delay.vdend + 0.005));
781 		break;
782 	default:
783 		E_Exit("This new machine needs implementation in VGA_VerticalTimer too.");
784 		break;
785 	}
786 	//Check if we can actually render, else skip the rest (frameskip)
787 	if (!RENDER_StartUpdate())
788 		return;
789 
790 	vga.draw.address_line = vga.config.hlines_skip;
791 	if (IS_EGAVGA_ARCH) {
792 		vga.draw.split_line = (Bitu)((vga.config.line_compare+1)/vga.draw.lines_scaled);
793 		if ((svgaCard==SVGA_S3Trio) && (vga.config.line_compare==0)) vga.draw.split_line=0;
794 		vga.draw.split_line -= vga.draw.vblank_skip;
795 	} else {
796 		vga.draw.split_line = 0x10000;	// don't care
797 	}
798 	vga.draw.address = vga.config.real_start;
799 	vga.draw.byte_panning_shift = 0;
800 	// go figure...
801 	if (machine==MCH_EGA) vga.draw.split_line*=2;
802 //	if (machine==MCH_EGA) vga.draw.split_line = ((((vga.config.line_compare&0x5ff)+1)*2-1)/vga.draw.lines_scaled);
803 #ifdef VGA_KEEP_CHANGES
804 	bool startaddr_changed=false;
805 #endif
806 	switch (vga.mode) {
807 	case M_EGA:
808 		if (!(vga.crtc.mode_control&0x1)) vga.draw.linear_mask &= ~0x10000;
809 		else vga.draw.linear_mask |= 0x10000;
810 	case M_LIN4:
811 		vga.draw.byte_panning_shift = 8;
812 		vga.draw.address += vga.draw.bytes_skip;
813 		vga.draw.address *= vga.draw.byte_panning_shift;
814 		vga.draw.address += vga.draw.panning;
815 #ifdef VGA_KEEP_CHANGES
816 		startaddr_changed=true;
817 #endif
818 		break;
819 	case M_VGA:
820 		if(vga.config.compatible_chain4 && (vga.crtc.underline_location & 0x40)) {
821 			vga.draw.linear_base = vga.fastmem;
822 			vga.draw.linear_mask = 0xffff;
823 		} else {
824 			vga.draw.linear_base = vga.mem.linear;
825 			vga.draw.linear_mask = vga.vmemwrap - 1;
826 		}
827 	case M_LIN8:
828 	case M_LIN15:
829 	case M_LIN16:
830 	case M_LIN32:
831 		vga.draw.byte_panning_shift = 4;
832 		vga.draw.address += vga.draw.bytes_skip;
833 		vga.draw.address *= vga.draw.byte_panning_shift;
834 		vga.draw.address += vga.draw.panning;
835 #ifdef VGA_KEEP_CHANGES
836 		startaddr_changed=true;
837 #endif
838 		break;
839 	case M_TEXT:
840 		vga.draw.byte_panning_shift = 2;
841 		vga.draw.address += vga.draw.bytes_skip;
842 		// fall-through
843 	case M_TANDY_TEXT:
844 	case M_HERC_TEXT:
845 		if (machine==MCH_HERC) vga.draw.linear_mask = 0xfff; // 1 page
846 		else if (IS_EGAVGA_ARCH) vga.draw.linear_mask = 0x7fff; // 8 pages
847 		else vga.draw.linear_mask = 0x3fff; // CGA, Tandy 4 pages
848 		vga.draw.cursor.address=vga.config.cursor_start*2;
849 		vga.draw.address *= 2;
850 		vga.draw.cursor.count++;
851 		/* check for blinking and blinking change delay */
852 		FontMask[1]=(vga.draw.blinking & (vga.draw.cursor.count >> 4)) ?
853 			0 : 0xffffffff;
854 		break;
855 	case M_HERC_GFX:
856 		break;
857 	case M_CGA4:case M_CGA2:
858 		vga.draw.address=(vga.draw.address*2)&0x1fff;
859 		break;
860 	case M_CGA16:
861 	case M_TANDY2:case M_TANDY4:case M_TANDY16:
862 		vga.draw.address *= 2;
863 		break;
864 	default:
865 		break;
866 	}
867 	if (GCC_UNLIKELY(vga.draw.split_line==0)) VGA_ProcessSplit();
868 #ifdef VGA_KEEP_CHANGES
869 	if (startaddr_changed) VGA_ChangesStart();
870 #endif
871 
872 	// check if some lines at the top off the screen are blanked
873 	float draw_skip = 0.0;
874 	if (GCC_UNLIKELY(vga.draw.vblank_skip)) {
875 		draw_skip = (float)(vga.draw.delay.htotal * vga.draw.vblank_skip);
876 		vga.draw.address += vga.draw.address_add * (vga.draw.vblank_skip/(vga.draw.address_line_total));
877 	}
878 
879 	// add the draw event
880 	switch (vga.draw.mode) {
881 	case PART:
882 		if (GCC_UNLIKELY(vga.draw.parts_left)) {
883 			LOG(LOG_VGAMISC,LOG_NORMAL)( "Parts left: %d", vga.draw.parts_left );
884 			PIC_RemoveEvents(VGA_DrawPart);
885 			RENDER_EndUpdate(true);
886 		}
887 		vga.draw.lines_done = 0;
888 		vga.draw.parts_left = vga.draw.parts_total;
889 		PIC_AddEvent(VGA_DrawPart,(float)vga.draw.delay.parts + draw_skip,vga.draw.parts_lines);
890 		break;
891 	case DRAWLINE:
892 		if (GCC_UNLIKELY(vga.draw.lines_done < vga.draw.lines_total)) {
893 			LOG(LOG_VGAMISC,LOG_NORMAL)( "Lines left: %d",
894 				vga.draw.lines_total-vga.draw.lines_done);
895 			PIC_RemoveEvents(VGA_DrawSingleLine);
896 			RENDER_EndUpdate(true);
897 		}
898 		vga.draw.lines_done = 0;
899 		PIC_AddEvent(VGA_DrawSingleLine,(float)(vga.draw.delay.htotal/4.0 + draw_skip));
900 		break;
901 	//case EGALINE:
902 	}
903 }
904 
VGA_CheckScanLength(void)905 void VGA_CheckScanLength(void) {
906 	switch (vga.mode) {
907 	case M_EGA:
908 	case M_LIN4:
909 		vga.draw.address_add=vga.config.scan_len*16;
910 		break;
911 	case M_VGA:
912 	case M_LIN8:
913 	case M_LIN15:
914 	case M_LIN16:
915 	case M_LIN32:
916 		vga.draw.address_add=vga.config.scan_len*8;
917 		break;
918 	case M_TEXT:
919 		vga.draw.address_add=vga.config.scan_len*4;
920 		break;
921 	case M_CGA2:
922 	case M_CGA4:
923 	case M_CGA16:
924 		vga.draw.address_add=80;
925 		return;
926 	case M_TANDY2:
927 		vga.draw.address_add=vga.draw.blocks/4;
928 		break;
929 	case M_TANDY4:
930 		vga.draw.address_add=vga.draw.blocks;
931 		break;
932 	case M_TANDY16:
933 		vga.draw.address_add=vga.draw.blocks;
934 		break;
935 	case M_TANDY_TEXT:
936 		vga.draw.address_add=vga.draw.blocks*2;
937 		break;
938 	case M_HERC_TEXT:
939 		vga.draw.address_add=vga.draw.blocks*2;
940 		break;
941 	case M_HERC_GFX:
942 		vga.draw.address_add=vga.draw.blocks;
943 		break;
944 	default:
945 		vga.draw.address_add=vga.draw.blocks*8;
946 		break;
947 	}
948 }
949 
VGA_ActivateHardwareCursor(void)950 void VGA_ActivateHardwareCursor(void) {
951 	bool hwcursor_active=false;
952 	if (svga.hardware_cursor_active) {
953 		if (svga.hardware_cursor_active()) hwcursor_active=true;
954 	}
955 	if (hwcursor_active) {
956 		switch(vga.mode) {
957 		case M_LIN32:
958 			VGA_DrawLine=VGA_Draw_LIN32_Line_HWMouse;
959 			break;
960 		case M_LIN15:
961 		case M_LIN16:
962 			VGA_DrawLine=VGA_Draw_LIN16_Line_HWMouse;
963 			break;
964 		default:
965 			VGA_DrawLine=VGA_Draw_VGA_Line_HWMouse;
966 		}
967 	} else {
968 		VGA_DrawLine=VGA_Draw_Linear_Line;
969 	}
970 }
971 
VGA_SetupDrawing(Bitu)972 void VGA_SetupDrawing(Bitu /*val*/) {
973 	if (vga.mode==M_ERROR) {
974 		PIC_RemoveEvents(VGA_VerticalTimer);
975 		PIC_RemoveEvents(VGA_PanningLatch);
976 		PIC_RemoveEvents(VGA_DisplayStartLatch);
977 		return;
978 	}
979 	// set the drawing mode
980 	switch (machine) {
981 	case MCH_CGA:
982 	case MCH_PCJR:
983 		vga.draw.mode = DRAWLINE;
984 		break;
985 	case MCH_VGA:
986 		if (svgaCard==SVGA_None) {
987 			vga.draw.mode = DRAWLINE;
988 			break;
989 		}
990 		// fall-through
991 	default:
992 		vga.draw.mode = PART;
993 		break;
994 	}
995 
996 	/* Calculate the FPS for this screen */
997 	double fps; Bitu clock;
998 	Bitu htotal, hdend, hbstart, hbend, hrstart, hrend;
999 	Bitu vtotal, vdend, vbstart, vbend, vrstart, vrend;
1000 	Bitu vblank_skip;
1001 	if (IS_EGAVGA_ARCH) {
1002 		htotal = vga.crtc.horizontal_total;
1003 		hdend = vga.crtc.horizontal_display_end;
1004 		hbend = vga.crtc.end_horizontal_blanking&0x1F;
1005 		hbstart = vga.crtc.start_horizontal_blanking;
1006 		hrstart = vga.crtc.start_horizontal_retrace;
1007 
1008 		vtotal= vga.crtc.vertical_total | ((vga.crtc.overflow & 1) << 8);
1009 		vdend = vga.crtc.vertical_display_end | ((vga.crtc.overflow & 2)<<7);
1010 		vbstart = vga.crtc.start_vertical_blanking | ((vga.crtc.overflow & 0x08) << 5);
1011 		vrstart = vga.crtc.vertical_retrace_start + ((vga.crtc.overflow & 0x04) << 6);
1012 
1013 		if (IS_VGA_ARCH) {
1014 			// additional bits only present on vga cards
1015 			htotal |= (vga.s3.ex_hor_overflow & 0x1) << 8;
1016 			htotal += 3;
1017 			hdend |= (vga.s3.ex_hor_overflow & 0x2) << 7;
1018 			hbend |= (vga.crtc.end_horizontal_retrace&0x80) >> 2;
1019 			hbstart |= (vga.s3.ex_hor_overflow & 0x4) << 6;
1020 			hrstart |= (vga.s3.ex_hor_overflow & 0x10) << 4;
1021 
1022 			vtotal |= (vga.crtc.overflow & 0x20) << 4;
1023 			vtotal |= (vga.s3.ex_ver_overflow & 0x1) << 10;
1024 			vdend |= (vga.crtc.overflow & 0x40) << 3;
1025 			vdend |= (vga.s3.ex_ver_overflow & 0x2) << 9;
1026 			vbstart |= (vga.crtc.maximum_scan_line & 0x20) << 4;
1027 			vbstart |= (vga.s3.ex_ver_overflow & 0x4) << 8;
1028 			vrstart |= ((vga.crtc.overflow & 0x80) << 2);
1029 			vrstart |= (vga.s3.ex_ver_overflow & 0x10) << 6;
1030 			vbend = vga.crtc.end_vertical_blanking & 0x7f;
1031 		} else { // EGA
1032 			vbend = vga.crtc.end_vertical_blanking & 0x1f;
1033 		}
1034 		htotal += 2;
1035 		vtotal += 2;
1036 		hdend += 1;
1037 		vdend += 1;
1038 		vbstart += 1;
1039 
1040 		hbend = hbstart + ((hbend - hbstart) & 0x3F);
1041 		hrend = vga.crtc.end_horizontal_retrace & 0x1f;
1042 		hrend = (hrend - hrstart) & 0x1f;
1043 
1044 		if ( !hrend ) hrend = hrstart + 0x1f + 1;
1045 		else hrend = hrstart + hrend;
1046 
1047 		vrend = vga.crtc.vertical_retrace_end & 0xF;
1048 		vrend = ( vrend - vrstart)&0xF;
1049 
1050 		if ( !vrend) vrend = vrstart + 0xf + 1;
1051 		else vrend = vrstart + vrend;
1052 
1053 		vbend = (vbend - vbstart) & 0x7f;
1054 		if ( !vbend) vbend = vbstart + 0x7f + 1;
1055 		else vbend = vbstart + vbend;
1056 
1057 		vbend++;
1058 
1059 		if (svga.get_clock) {
1060 			clock = svga.get_clock();
1061 		} else {
1062 			switch ((vga.misc_output >> 2) & 3) {
1063 			case 0:
1064 				clock = (machine==MCH_EGA) ? 14318180 : 25175000;
1065 				break;
1066 			case 1:
1067 			default:
1068 				clock = (machine==MCH_EGA) ? 16257000 : 28322000;
1069 				break;
1070 			}
1071 		}
1072 
1073 		/* Check for 8 for 9 character clock mode */
1074 		if (vga.seq.clocking_mode & 1 ) clock/=8; else clock/=9;
1075 		/* Check for pixel doubling, master clock/2 */
1076 		if (vga.seq.clocking_mode & 0x8) {
1077 			htotal*=2;
1078 		}
1079 		vga.draw.address_line_total=(vga.crtc.maximum_scan_line&0x1f)+1;
1080 		if(IS_VGA_ARCH && (svgaCard==SVGA_None) && (vga.mode==M_EGA || vga.mode==M_VGA)) {
1081 			// vgaonly; can't use with CGA because these use address_line for their
1082 			// own purposes.
1083 			// Set the low resolution modes to have as many lines as are scanned -
1084 			// Quite a few demos change the max_scanline register at display time
1085 			// to get SFX: Majic12 show, Magic circle, Copper, GBU, Party91
1086 			if( vga.crtc.maximum_scan_line&0x80) vga.draw.address_line_total*=2;
1087 			vga.draw.double_scan=false;
1088 		}
1089 		else if (IS_VGA_ARCH) vga.draw.double_scan=(vga.crtc.maximum_scan_line&0x80)>0;
1090 		else vga.draw.double_scan=(vtotal==262);
1091 	} else {
1092 		htotal = vga.other.htotal + 1;
1093 		hdend = vga.other.hdend;
1094 		hbstart = hdend;
1095 		hbend = htotal;
1096 		hrstart = vga.other.hsyncp;
1097 		hrend = hrstart + vga.other.hsyncw;
1098 
1099 		vga.draw.address_line_total = vga.other.max_scanline + 1;
1100 		vtotal = vga.draw.address_line_total * (vga.other.vtotal+1)+vga.other.vadjust;
1101 		vdend = vga.draw.address_line_total * vga.other.vdend;
1102 		vrstart = vga.draw.address_line_total * vga.other.vsyncp;
1103 		vrend = vrstart + 16; // vsync width is fixed to 16 lines on the MC6845 TODO Tandy
1104 		vbstart = vdend;
1105 		vbend = vtotal;
1106 		vga.draw.double_scan=false;
1107 		switch (machine) {
1108 		case MCH_CGA:
1109 		case TANDY_ARCH_CASE:
1110 			clock=((vga.tandy.mode_control & 1) ? 14318180 : (14318180/2))/8;
1111 			break;
1112 		case MCH_HERC:
1113 			if (vga.herc.mode_control & 0x2) clock=16000000/16;
1114 			else clock=16000000/8;
1115 			break;
1116 		default:
1117 			clock = 14318180;
1118 			break;
1119 		}
1120 		vga.draw.delay.hdend = hdend*1000.0/clock; //in milliseconds
1121 	}
1122 #if C_DEBUG
1123 	LOG(LOG_VGA,LOG_NORMAL)("h total %d end %d blank (%d/%d) retrace (%d/%d)",
1124 		htotal, hdend, hbstart, hbend, hrstart, hrend );
1125 	LOG(LOG_VGA,LOG_NORMAL)("v total %d end %d blank (%d/%d) retrace (%d/%d)",
1126 		vtotal, vdend, vbstart, vbend, vrstart, vrend );
1127 #endif
1128 	if (!htotal) return;
1129 	if (!vtotal) return;
1130 
1131 	// The screen refresh frequency
1132 	fps=(double)clock/(vtotal*htotal);
1133 	// Horizontal total (that's how long a line takes with whistles and bells)
1134 	vga.draw.delay.htotal = htotal*1000.0/clock; //in milliseconds
1135 	// Start and End of horizontal blanking
1136 	vga.draw.delay.hblkstart = hbstart*1000.0/clock; //in milliseconds
1137 	vga.draw.delay.hblkend = hbend*1000.0/clock;
1138 	// Start and End of horizontal retrace
1139 	vga.draw.delay.hrstart = hrstart*1000.0/clock;
1140 	vga.draw.delay.hrend = hrend*1000.0/clock;
1141 	// Start and End of vertical blanking
1142 	vga.draw.delay.vblkstart = vbstart * vga.draw.delay.htotal;
1143 	vga.draw.delay.vblkend = vbend * vga.draw.delay.htotal;
1144 	// Start and End of vertical retrace pulse
1145 	vga.draw.delay.vrstart = vrstart * vga.draw.delay.htotal;
1146 	vga.draw.delay.vrend = vrend * vga.draw.delay.htotal;
1147 
1148 	// Vertical blanking tricks
1149 	vblank_skip = 0;
1150 	if (IS_VGA_ARCH) { // others need more investigation
1151 		if (vbend > vtotal) {
1152 			// blanking wraps to the start of the screen
1153 			vblank_skip = vbend&0x7f;
1154 
1155 			// on blanking wrap to 0, the first line is not blanked
1156 			// this is used by the S3 BIOS and other S3 drivers in some SVGA modes
1157 			if((vbend&0x7f)==1) vblank_skip = 0;
1158 
1159 			// it might also cut some lines off the bottom
1160 			if(vbstart < vdend) {
1161 				vdend = vbstart;
1162 			}
1163 			LOG(LOG_VGA,LOG_WARN)("Blanking wrap to line %d", vblank_skip);
1164 		} else if (vbstart==1) {
1165 			// blanking is used to cut lines at the start of the screen
1166 			vblank_skip = vbend;
1167 			LOG(LOG_VGA,LOG_WARN)("Upper %d lines of the screen blanked", vblank_skip);
1168 		} else if (vbstart < vdend) {
1169 			if(vbend < vdend) {
1170 				// the game wants a black bar somewhere on the screen
1171 				LOG(LOG_VGA,LOG_WARN)("Unsupported blanking: line %d-%d",vbstart,vbend);
1172 			} else {
1173 				// blanking is used to cut off some lines from the bottom
1174 				vdend = vbstart;
1175 			}
1176 		}
1177 		vdend -= vblank_skip;
1178 	}
1179 	// Display end
1180 	vga.draw.delay.vdend = vdend * vga.draw.delay.htotal;
1181 
1182 	vga.draw.parts_total=VGA_PARTS;
1183 	/*
1184       6  Horizontal Sync Polarity. Negative if set
1185       7  Vertical Sync Polarity. Negative if set
1186          Bit 6-7 indicates the number of lines on the display:
1187             1:  400, 2: 350, 3: 480
1188 	*/
1189 	//Try to determine the pixel size, aspect correct is based around square pixels
1190 
1191 	//Base pixel width around 100 clocks horizontal
1192 	//For 9 pixel text modes this should be changed, but we don't support that anyway :)
1193 	//Seems regular vga only listens to the 9 char pixel mode with character mode enabled
1194 	double pwidth = (machine==MCH_EGA) ? (114.0 / htotal) : (100.0 / htotal);
1195 	//Base pixel height around vertical totals of modes that have 100 clocks horizontal
1196 	//Different sync values gives different scaling of the whole vertical range
1197 	//VGA monitor just seems to thighten or widen the whole vertical range
1198 	double pheight;
1199 	double target_total = (machine==MCH_EGA) ? 262.0 : 449.0;
1200 	Bitu sync = vga.misc_output >> 6;
1201 	switch ( sync ) {
1202 	case 0:		// This is not defined in vga specs,
1203 				// Kiet, seems to be slightly less than 350 on my monitor
1204 		//340 line mode, filled with 449 total
1205 		pheight = (480.0 / 340.0) * ( target_total / vtotal );
1206 		break;
1207 	case 1:		//400 line mode, filled with 449 total
1208 		pheight = (480.0 / 400.0) * ( target_total / vtotal );
1209 		break;
1210 	case 2:		//350 line mode, filled with 449 total
1211 		//This mode seems to get regular 640x400 timing and goes for a loong retrace
1212 		//Depends on the monitor to stretch the screen
1213 		pheight = (480.0 / 350.0) * ( target_total / vtotal );
1214 		break;
1215 	case 3:		//480 line mode, filled with 525 total
1216 	default:
1217 		pheight = (480.0 / 480.0) * ( 525.0 / vtotal );
1218 		break;
1219 	}
1220 
1221 	double aspect_ratio = pheight / pwidth;
1222 
1223 	vga.draw.delay.parts = vga.draw.delay.vdend/vga.draw.parts_total;
1224 	vga.draw.resizing=false;
1225 	vga.draw.vret_triggered=false;
1226 
1227 	//Check to prevent useless black areas
1228 	if (hbstart<hdend) hdend=hbstart;
1229 	if ((!IS_VGA_ARCH) && (vbstart<vdend)) vdend=vbstart;
1230 
1231 
1232 	Bitu width=hdend;
1233 	Bitu height=vdend;
1234 	bool doubleheight=false;
1235 	bool doublewidth=false;
1236 
1237 	//Set the bpp
1238 	Bitu bpp;
1239 	switch (vga.mode) {
1240 	case M_LIN15:
1241 		bpp = 15;
1242 		break;
1243 	case M_LIN16:
1244 		bpp = 16;
1245 		break;
1246 	case M_LIN32:
1247 		bpp = 32;
1248 		break;
1249 	default:
1250 		bpp = 8;
1251 		break;
1252 	}
1253 	vga.draw.linear_base = vga.mem.linear;
1254 	vga.draw.linear_mask = vga.vmemwrap - 1;
1255 	switch (vga.mode) {
1256 	case M_VGA:
1257 		doublewidth=true;
1258 		width<<=2;
1259 		if ((IS_VGA_ARCH) && (svgaCard==SVGA_None)) {
1260 			bpp=16;
1261 			VGA_DrawLine = VGA_Draw_Xlat16_Linear_Line;
1262 		} else VGA_DrawLine = VGA_Draw_Linear_Line;
1263 		break;
1264 	case M_LIN8:
1265 		if (vga.crtc.mode_control & 0x8)
1266 			width >>=1;
1267 		else if(svgaCard == SVGA_S3Trio && !(vga.s3.reg_3a&0x10)) {
1268 			doublewidth=true;
1269 			width >>=1;
1270 		}
1271 		// fall-through
1272 	case M_LIN32:
1273 		width<<=3;
1274 		if (vga.crtc.mode_control & 0x8)
1275  			doublewidth = true;
1276 		/* Use HW mouse cursor drawer if enabled */
1277 		VGA_ActivateHardwareCursor();
1278 		break;
1279 	case M_LIN15:
1280  	case M_LIN16:
1281 		// 15/16 bpp modes double the horizontal values
1282 		width<<=2;
1283 		if ((vga.crtc.mode_control & 0x8) || (svgaCard == SVGA_S3Trio && (vga.s3.pll.cmd & 0x10)))
1284 			doublewidth = true;
1285 		/* Use HW mouse cursor drawer if enabled */
1286 		VGA_ActivateHardwareCursor();
1287 		break;
1288 	case M_LIN4:
1289 		doublewidth=(vga.seq.clocking_mode & 0x8) > 0;
1290 		vga.draw.blocks = width;
1291 		width<<=3;
1292 		VGA_DrawLine=VGA_Draw_Linear_Line;
1293 		vga.draw.linear_base = vga.fastmem;
1294 		vga.draw.linear_mask = (vga.vmemwrap<<1) - 1;
1295 		break;
1296 	case M_EGA:
1297 		doublewidth=(vga.seq.clocking_mode & 0x8) > 0;
1298 		vga.draw.blocks = width;
1299 		width<<=3;
1300 		if ((IS_VGA_ARCH) && (svgaCard==SVGA_None)) {
1301 			bpp=16;
1302 			VGA_DrawLine = VGA_Draw_Xlat16_Linear_Line;
1303 		} else VGA_DrawLine=VGA_Draw_Linear_Line;
1304 
1305 		vga.draw.linear_base = vga.fastmem;
1306 		vga.draw.linear_mask = (vga.vmemwrap<<1) - 1;
1307 		break;
1308 	case M_CGA16:
1309 		doubleheight=true;
1310 		vga.draw.blocks=width*2;
1311 		width<<=4;
1312 		VGA_DrawLine=VGA_Draw_CGA16_Line;
1313 		break;
1314 	case M_CGA4:
1315 		doublewidth=true;
1316 		vga.draw.blocks=width*2;
1317 		width<<=3;
1318 		VGA_DrawLine=VGA_Draw_2BPP_Line;
1319 		break;
1320 	case M_CGA2:
1321 		doubleheight=true;
1322 		vga.draw.blocks=2*width;
1323 		width<<=3;
1324 		VGA_DrawLine=VGA_Draw_1BPP_Line;
1325 		break;
1326 	case M_TEXT:
1327 		aspect_ratio=1.0;
1328 		vga.draw.blocks=width;
1329 		doublewidth=(vga.seq.clocking_mode & 0x8) > 0;
1330 		if ((IS_VGA_ARCH) && (svgaCard==SVGA_None) && !(vga.seq.clocking_mode&0x01)) {
1331 			width*=9;				/* 9 bit wide text font */
1332 			VGA_DrawLine=VGA_TEXT_Xlat16_Draw_Line_9;
1333 			bpp=16;
1334 //			VGA_DrawLine=VGA_TEXT_Draw_Line_9;
1335 		} else {
1336 			width<<=3;				/* 8 bit wide text font */
1337 			if ((IS_VGA_ARCH) && (svgaCard==SVGA_None)) {
1338 				VGA_DrawLine=VGA_TEXT_Xlat16_Draw_Line;
1339 				bpp=16;
1340 			} else VGA_DrawLine=VGA_TEXT_Draw_Line;
1341 		}
1342 		break;
1343 	case M_HERC_GFX:
1344 		aspect_ratio=1.5;
1345 		vga.draw.blocks=width*2;
1346 		width*=16;
1347 		VGA_DrawLine=VGA_Draw_1BPP_Line;
1348 		break;
1349 	case M_TANDY2:
1350 		aspect_ratio=1.2;
1351 		doubleheight=true;
1352 		if (machine==MCH_PCJR) doublewidth=(vga.tandy.gfx_control & 0x8)==0x00;
1353 		else doublewidth=(vga.tandy.mode_control & 0x10)==0;
1354 		vga.draw.blocks=width * (doublewidth ? 4:8);
1355 		width=vga.draw.blocks*2;
1356 		VGA_DrawLine=VGA_Draw_1BPP_Line;
1357 		break;
1358 	case M_TANDY4:
1359 		aspect_ratio=1.2;
1360 		doubleheight=true;
1361 		if (machine==MCH_TANDY) doublewidth=(vga.tandy.mode_control & 0x10)==0;
1362 		else doublewidth=(vga.tandy.mode_control & 0x01)==0x00;
1363 		vga.draw.blocks=width * 2;
1364 		width=vga.draw.blocks*4;
1365 		if ((machine==MCH_TANDY && (vga.tandy.gfx_control & 0x8)) ||
1366 			(machine==MCH_PCJR && (vga.tandy.mode_control==0x0b)))
1367 			VGA_DrawLine=VGA_Draw_2BPPHiRes_Line;
1368 		else VGA_DrawLine=VGA_Draw_2BPP_Line;
1369 		break;
1370 	case M_TANDY16:
1371 		aspect_ratio=1.2;
1372 		doubleheight=true;
1373 		vga.draw.blocks=width*2;
1374 		if (vga.tandy.mode_control & 0x1) {
1375 			if (( machine==MCH_TANDY ) && ( vga.tandy.mode_control & 0x10 )) {
1376 				doublewidth = false;
1377 				vga.draw.blocks*=2;
1378 				width=vga.draw.blocks*2;
1379 			} else {
1380 				doublewidth = true;
1381 				width=vga.draw.blocks*2;
1382 			}
1383 			VGA_DrawLine=VGA_Draw_4BPP_Line;
1384 		} else {
1385 			doublewidth=true;
1386 			width=vga.draw.blocks*4;
1387 			VGA_DrawLine=VGA_Draw_4BPP_Line_Double;
1388 		}
1389 		break;
1390 	case M_TANDY_TEXT:
1391 		doublewidth=(vga.tandy.mode_control & 0x1)==0;
1392 		aspect_ratio=1;
1393 		doubleheight=true;
1394 		vga.draw.blocks=width;
1395 		width<<=3;
1396 		VGA_DrawLine=VGA_TEXT_Draw_Line;
1397 		break;
1398 	case M_HERC_TEXT:
1399 		aspect_ratio=1;
1400 		vga.draw.blocks=width;
1401 		width<<=3;
1402 		VGA_DrawLine=VGA_TEXT_Herc_Draw_Line;
1403 		break;
1404 	default:
1405 		LOG(LOG_VGA,LOG_ERROR)("Unhandled VGA mode %d while checking for resolution",vga.mode);
1406 		break;
1407 	}
1408 	VGA_CheckScanLength();
1409 	if (vga.draw.double_scan) {
1410 		if (IS_VGA_ARCH) {
1411 			vga.draw.vblank_skip /= 2;
1412 			height/=2;
1413 		}
1414 		doubleheight=true;
1415 	}
1416 	vga.draw.vblank_skip = vblank_skip;
1417 
1418 	if(!(IS_VGA_ARCH && (svgaCard==SVGA_None) && (vga.mode==M_EGA || vga.mode==M_VGA))) {
1419 		//Only check for extra double height in vga modes
1420 		//(line multiplying by address_line_total)
1421 		if (!doubleheight && (vga.mode<M_TEXT) && !(vga.draw.address_line_total & 1)) {
1422 			vga.draw.address_line_total/=2;
1423 			doubleheight=true;
1424 			height/=2;
1425 		}
1426 	}
1427 	vga.draw.lines_total=height;
1428 	vga.draw.parts_lines=vga.draw.lines_total/vga.draw.parts_total;
1429 	vga.draw.line_length = width * ((bpp + 1) / 8);
1430 #ifdef VGA_KEEP_CHANGES
1431 	vga.changes.active = false;
1432 	vga.changes.frame = 0;
1433 	vga.changes.writeMask = 1;
1434 #endif
1435     /*
1436 	   Cheap hack to just make all > 640x480 modes have 4:3 aspect ratio
1437 	*/
1438 	if ( width >= 640 && height >= 480 ) {
1439 		aspect_ratio = ((float)width / (float)height) * ( 3.0 / 4.0);
1440 	}
1441 //	LOG_MSG("ht %d vt %d ratio %f", htotal, vtotal, aspect_ratio );
1442 
1443 	bool fps_changed = false;
1444 	// need to change the vertical timing?
1445 	if (fabs(vga.draw.delay.vtotal - 1000.0 / fps) > 0.0001) {
1446 		fps_changed = true;
1447 		vga.draw.delay.vtotal = 1000.0 / fps;
1448 		VGA_KillDrawing();
1449 		PIC_RemoveEvents(VGA_Other_VertInterrupt);
1450 		PIC_RemoveEvents(VGA_VerticalTimer);
1451 		PIC_RemoveEvents(VGA_PanningLatch);
1452 		PIC_RemoveEvents(VGA_DisplayStartLatch);
1453 		VGA_VerticalTimer(0);
1454 	}
1455 
1456 #if C_DEBUG
1457 	LOG(LOG_VGA,LOG_NORMAL)("h total %2.5f (%3.2fkHz) blank(%02.5f/%02.5f) retrace(%02.5f/%02.5f)",
1458 		vga.draw.delay.htotal,(1.0/vga.draw.delay.htotal),
1459 		vga.draw.delay.hblkstart,vga.draw.delay.hblkend,
1460 		vga.draw.delay.hrstart,vga.draw.delay.hrend);
1461 	LOG(LOG_VGA,LOG_NORMAL)("v total %2.5f (%3.2fHz) blank(%02.5f/%02.5f) retrace(%02.5f/%02.5f)",
1462 		vga.draw.delay.vtotal,(1000.0/vga.draw.delay.vtotal),
1463 		vga.draw.delay.vblkstart,vga.draw.delay.vblkend,
1464 		vga.draw.delay.vrstart,vga.draw.delay.vrend);
1465 #endif
1466 
1467 	// need to resize the output window?
1468 	if ((width != vga.draw.width) ||
1469 		(height != vga.draw.height) ||
1470 		(vga.draw.doublewidth != doublewidth) ||
1471 		(vga.draw.doubleheight != doubleheight) ||
1472 		(fabs(aspect_ratio - vga.draw.aspect_ratio) > 0.0001) ||
1473 		(vga.draw.bpp != bpp) || fps_changed) {
1474 
1475 		VGA_KillDrawing();
1476 
1477 		vga.draw.width = width;
1478 		vga.draw.height = height;
1479 		vga.draw.doublewidth = doublewidth;
1480 		vga.draw.doubleheight = doubleheight;
1481 		vga.draw.aspect_ratio = aspect_ratio;
1482 		vga.draw.bpp = bpp;
1483 		if (doubleheight) vga.draw.lines_scaled=2;
1484 		else vga.draw.lines_scaled=1;
1485 #if C_DEBUG
1486 		LOG(LOG_VGA,LOG_NORMAL)("Width %d, Height %d, fps %f",width,height,fps);
1487 		LOG(LOG_VGA,LOG_NORMAL)("%s width, %s height aspect %f",
1488 			doublewidth ? "double":"normal",doubleheight ? "double":"normal",aspect_ratio);
1489 #endif
1490 		RENDER_SetSize(width,height,bpp,(float)fps,aspect_ratio,doublewidth,doubleheight);
1491 	}
1492 }
1493 
VGA_KillDrawing(void)1494 void VGA_KillDrawing(void) {
1495 	PIC_RemoveEvents(VGA_DrawPart);
1496 	PIC_RemoveEvents(VGA_DrawSingleLine);
1497 	vga.draw.parts_left = 0;
1498 	vga.draw.lines_done = ~0;
1499 	RENDER_EndUpdate(true);
1500 }
1501