1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (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.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 */
20 //
21 // vid_ext.c: extended video modes
22 // in this implementation, VESA-specific DOS video stuff
23 //
24 
25 // TODO: make dependencies on vid_vga.c explicit or eliminate them
26 
27 #include <stdlib.h>
28 #include <dos.h>
29 
30 #include "quakedef.h"
31 #include "d_local.h"
32 #include "dosisms.h"
33 #include "vid_dos.h"
34 #include <dpmi.h>
35 
36 #define MODE_SUPPORTED_IN_HW	0x0001
37 #define COLOR_MODE				0x0008
38 #define GRAPHICS_MODE			0x0010
39 #define VGA_INCOMPATIBLE		0x0020
40 #define LINEAR_FRAME_BUFFER		0x0080
41 
42 #define LINEAR_MODE				0x4000
43 
44 #define VESA_DONT_WAIT_VSYNC	0		// when page flipping
45 #define VESA_WAIT_VSYNC			0x80
46 
47 #define MAX_VESA_MODES			30	// we'll just take the first 30 if there
48 									//  are more
49 typedef struct {
50 	int			pages[3];			// either 2 or 3 is valid
51 	int			vesamode;			// LINEAR_MODE set if linear mode
52 	void		*plinearmem;		// linear address of start of frame buffer
53 	qboolean	vga_incompatible;
54 } vesa_extra_t;
55 
56 static vmode_t		vesa_modes[MAX_VESA_MODES] =
57 	{{NULL, NULL, "    ********* VESA modes *********    "}};
58 static vesa_extra_t	vesa_extra[MAX_VESA_MODES];
59 static char			names[MAX_VESA_MODES][10];
60 
61 extern regs_t regs;
62 
63 static int		VID_currentpage;
64 static int		VID_displayedpage;
65 static int		*VID_pagelist;
66 static byte		*VID_membase;
67 static int		VID_banked;
68 
69 typedef struct
70 {
71 	int modenum;
72 	int mode_attributes;
73 	int	winasegment;
74 	int	winbsegment;
75 	int	bytes_per_scanline; // bytes per logical scanline (+16)
76 	int win; // window number (A=0, B=1)
77 	int win_size; // window size (+6)
78 	int granularity; // how finely i can set the window in vid mem (+4)
79 	int width, height; // displayed width and height (+18, +20)
80 	int bits_per_pixel; // er, better be 8, 15, 16, 24, or 32 (+25)
81 	int bytes_per_pixel; // er, better be 1, 2, or 4
82 	int memory_model; // and better be 4 or 6, packed or direct color (+27)
83 	int num_pages; // number of complete frame buffer pages (+29)
84 	int red_width; // the # of bits in the red component (+31)
85 	int red_pos; // the bit position of the red component (+32)
86 	int green_width; // etc.. (+33)
87 	int green_pos; // (+34)
88 	int blue_width; // (+35)
89 	int blue_pos; // (+36)
90 	int pptr;
91 	int	pagesize;
92 	int	numpages;
93 } modeinfo_t;
94 
95 static modeinfo_t modeinfo;
96 
97 // all bytes to avoid problems with compiler field packing
98 typedef struct vbeinfoblock_s {
99      byte			VbeSignature[4];
100      byte			VbeVersion[2];
101      byte			OemStringPtr[4];
102      byte			Capabilities[4];
103      byte			VideoModePtr[4];
104      byte			TotalMemory[2];
105      byte			OemSoftwareRev[2];
106      byte			OemVendorNamePtr[4];
107      byte			OemProductNamePtr[4];
108      byte			OemProductRevPtr[4];
109      byte			Reserved[222];
110      byte			OemData[256];
111 } vbeinfoblock_t;
112 
113 static int	totalvidmem;
114 static byte	*ppal;
115 qboolean	vsync_exists, de_exists;
116 
117 qboolean VID_ExtraGetModeInfo(int modenum);
118 int VID_ExtraInitMode (viddef_t *vid, vmode_t *pcurrentmode);
119 void VID_ExtraSwapBuffers (viddef_t *vid, vmode_t *pcurrentmode,
120 	vrect_t *rects);
121 
122 
123 /*
124 ================
125 VGA_BankedBeginDirectRect
126 ================
127 */
VGA_BankedBeginDirectRect(viddef_t * lvid,struct vmode_s * pcurrentmode,int x,int y,byte * pbitmap,int width,int height)128 void VGA_BankedBeginDirectRect (viddef_t *lvid, struct vmode_s *pcurrentmode,
129 	int x, int y, byte *pbitmap, int width, int height)
130 {
131 
132 	if (!lvid->direct)
133 		return;
134 
135 	regs.x.ax = 0x4f05;
136 	regs.x.bx = 0;
137 	regs.x.dx = VID_displayedpage;
138 	dos_int86(0x10);
139 
140 	VGA_BeginDirectRect (lvid, pcurrentmode, x, y, pbitmap, width, height);
141 
142 	regs.x.ax = 0x4f05;
143 	regs.x.bx = 0;
144 	regs.x.dx = VID_currentpage;
145 	dos_int86(0x10);
146 }
147 
148 
149 /*
150 ================
151 VGA_BankedEndDirectRect
152 ================
153 */
VGA_BankedEndDirectRect(viddef_t * lvid,struct vmode_s * pcurrentmode,int x,int y,int width,int height)154 void VGA_BankedEndDirectRect (viddef_t *lvid, struct vmode_s *pcurrentmode,
155 	int x, int y, int width, int height)
156 {
157 
158 	if (!lvid->direct)
159 		return;
160 
161 	regs.x.ax = 0x4f05;
162 	regs.x.bx = 0;
163 	regs.x.dx = VID_displayedpage;
164 	dos_int86(0x10);
165 
166 	VGA_EndDirectRect (lvid, pcurrentmode, x, y, width, height);
167 
168 	regs.x.ax = 0x4f05;
169 	regs.x.bx = 0;
170 	regs.x.dx = VID_currentpage;
171 	dos_int86(0x10);
172 }
173 
174 
175 /*
176 ================
177 VID_SetVESAPalette
178 ================
179 */
VID_SetVESAPalette(viddef_t * lvid,vmode_t * pcurrentmode,unsigned char * pal)180 void VID_SetVESAPalette (viddef_t *lvid, vmode_t *pcurrentmode,
181 	unsigned char *pal)
182 {
183 	int		i;
184 	byte	*pp;
185 
186 	UNUSED(lvid);
187 	UNUSED(pcurrentmode);
188 
189 	pp = ppal;
190 
191 	for (i=0 ; i<256 ; i++)
192 	{
193 		pp[2] = pal[0] >> 2;
194 		pp[1] = pal[1] >> 2;
195 		pp[0] = pal[2] >> 2;
196 		pp += 4;
197 		pal += 3;
198 	}
199 
200 	regs.x.ax = 0x4F09;
201 	regs.x.bx = 0;
202 	regs.x.cx = 256;
203 	regs.x.dx = 0;
204 	regs.x.es = ptr2real(ppal) >> 4;
205 	regs.x.di = ptr2real(ppal) & 0xf;
206 	dos_int86(0x10);
207 
208 	if (regs.x.ax != 0x4f)
209 		Sys_Error ("Unable to load VESA palette\n");
210 }
211 
212 
213 
214 
215 /*
216 ================
217 VID_ExtraFarToLinear
218 ================
219 */
VID_ExtraFarToLinear(void * ptr)220 void *VID_ExtraFarToLinear (void *ptr)
221 {
222 	int		temp;
223 
224 	temp = (int)ptr;
225 	return real2ptr(((temp & 0xFFFF0000) >> 12) + (temp & 0xFFFF));
226 }
227 
228 
229 /*
230 ================
231 VID_ExtraWaitDisplayEnable
232 ================
233 */
VID_ExtraWaitDisplayEnable()234 void VID_ExtraWaitDisplayEnable ()
235 {
236 	while ((inportb (0x3DA) & 0x01) == 1)
237 		;
238 }
239 
240 
241 /*
242 ================
243 VID_ExtraVidLookForState
244 ================
245 */
VID_ExtraVidLookForState(unsigned state,unsigned mask)246 qboolean VID_ExtraVidLookForState (unsigned state, unsigned mask)
247 {
248 	int		i;
249 	double	starttime, time;
250 
251 	starttime = Sys_FloatTime ();
252 
253 	do
254 	{
255 		for (i=0 ; i<100000 ; i++)
256 		{
257 			if ((inportb (0x3DA) & mask) == state)
258 				return true;
259 		}
260 
261 		time = Sys_FloatTime ();
262 	} while ((time - starttime) < 0.1);
263 
264 	return false;
265 }
266 
267 
268 /*
269 ================
270 VID_ExtraStateFound
271 ================
272 */
VID_ExtraStateFound(unsigned state)273 qboolean VID_ExtraStateFound (unsigned state)
274 {
275 	int		i, workingstate;
276 
277 	workingstate = 0;
278 
279 	for (i=0 ; i<10 ; i++)
280 	{
281 		if (!VID_ExtraVidLookForState(workingstate, state))
282 		{
283 			return false;
284 		}
285 
286 		workingstate ^= state;
287 	}
288 
289 	return true;
290 }
291 
292 
293 /*
294 ================
295 VID_InitExtra
296 ================
297 */
VID_InitExtra(void)298 void VID_InitExtra (void)
299 {
300 	int				nummodes;
301 	short			*pmodenums;
302 	vbeinfoblock_t	*pinfoblock;
303 	__dpmi_meminfo	phys_mem_info;
304 
305 	pinfoblock = dos_getmemory(sizeof(vbeinfoblock_t));
306 
307 	*(long *)pinfoblock->VbeSignature = 'V' + ('B'<<8) + ('E'<<16) + ('2'<<24);
308 
309 // see if VESA support is available
310 	regs.x.ax = 0x4f00;
311 	regs.x.es = ptr2real(pinfoblock) >> 4;
312 	regs.x.di = ptr2real(pinfoblock) & 0xf;
313 	dos_int86(0x10);
314 
315 	if (regs.x.ax != 0x4f)
316 		return;		// no VESA support
317 
318 	if (pinfoblock->VbeVersion[1] < 0x02)
319 		return;		// not VESA 2.0 or greater
320 
321 	Con_Printf ("VESA 2.0 compliant adapter:\n%s\n",
322 				VID_ExtraFarToLinear (*(byte **)&pinfoblock->OemStringPtr[0]));
323 
324 	totalvidmem = *(unsigned short *)&pinfoblock->TotalMemory[0] << 16;
325 
326 	pmodenums = (short *)
327 			VID_ExtraFarToLinear (*(byte **)&pinfoblock->VideoModePtr[0]);
328 
329 // find 8 bit modes until we either run out of space or run out of modes
330 	nummodes = 0;
331 
332 	while ((*pmodenums != -1) && (nummodes < MAX_VESA_MODES))
333 	{
334 		if (VID_ExtraGetModeInfo (*pmodenums))
335 		{
336 			vesa_modes[nummodes].pnext = &vesa_modes[nummodes+1];
337 			if (modeinfo.width > 999)
338 			{
339 				if (modeinfo.height > 999)
340 				{
341 					sprintf (&names[nummodes][0], "%4dx%4d", modeinfo.width,
342 							 modeinfo.height);
343 					names[nummodes][9] = 0;
344 				}
345 				else
346 				{
347 					sprintf (&names[nummodes][0], "%4dx%3d", modeinfo.width,
348 							 modeinfo.height);
349 					names[nummodes][8] = 0;
350 				}
351 			}
352 			else
353 			{
354 				if (modeinfo.height > 999)
355 				{
356 					sprintf (&names[nummodes][0], "%3dx%4d", modeinfo.width,
357 							 modeinfo.height);
358 					names[nummodes][8] = 0;
359 				}
360 				else
361 				{
362 					sprintf (&names[nummodes][0], "%3dx%3d", modeinfo.width,
363 							 modeinfo.height);
364 					names[nummodes][7] = 0;
365 				}
366 			}
367 
368 			vesa_modes[nummodes].name = &names[nummodes][0];
369 			vesa_modes[nummodes].width = modeinfo.width;
370 			vesa_modes[nummodes].height = modeinfo.height;
371 			vesa_modes[nummodes].aspect =
372 					((float)modeinfo.height / (float)modeinfo.width) *
373 					(320.0 / 240.0);
374 			vesa_modes[nummodes].rowbytes = modeinfo.bytes_per_scanline;
375 			vesa_modes[nummodes].planar = 0;
376 			vesa_modes[nummodes].pextradata = &vesa_extra[nummodes];
377 			vesa_modes[nummodes].setmode = VID_ExtraInitMode;
378 			vesa_modes[nummodes].swapbuffers = VID_ExtraSwapBuffers;
379 			vesa_modes[nummodes].setpalette = VID_SetVESAPalette;
380 
381 			if (modeinfo.mode_attributes & LINEAR_FRAME_BUFFER)
382 			{
383 			// add linear bit to mode for linear modes
384 				vesa_extra[nummodes].vesamode = modeinfo.modenum | LINEAR_MODE;
385 				vesa_extra[nummodes].pages[0] = 0;
386 				vesa_extra[nummodes].pages[1] = modeinfo.pagesize;
387 				vesa_extra[nummodes].pages[2] = modeinfo.pagesize * 2;
388 				vesa_modes[nummodes].numpages = modeinfo.numpages;
389 
390 				vesa_modes[nummodes].begindirectrect = VGA_BeginDirectRect;
391 				vesa_modes[nummodes].enddirectrect = VGA_EndDirectRect;
392 
393 				phys_mem_info.address = (int)modeinfo.pptr;
394 				phys_mem_info.size = 0x400000;
395 
396 				if (__dpmi_physical_address_mapping(&phys_mem_info))
397 					goto NextMode;
398 
399 				vesa_extra[nummodes].plinearmem =
400 						 real2ptr (phys_mem_info.address);
401 			}
402 			else
403 			{
404 			// banked at 0xA0000
405 				vesa_extra[nummodes].vesamode = modeinfo.modenum;
406 				vesa_extra[nummodes].pages[0] = 0;
407 				vesa_extra[nummodes].plinearmem =
408 						real2ptr(modeinfo.winasegment<<4);
409 
410 				vesa_modes[nummodes].begindirectrect =
411 						VGA_BankedBeginDirectRect;
412 				vesa_modes[nummodes].enddirectrect = VGA_BankedEndDirectRect;
413 				vesa_extra[nummodes].pages[1] = modeinfo.pagesize;
414 				vesa_extra[nummodes].pages[2] = modeinfo.pagesize * 2;
415 				vesa_modes[nummodes].numpages = modeinfo.numpages;
416 			}
417 
418 			vesa_extra[nummodes].vga_incompatible =
419 					modeinfo.mode_attributes & VGA_INCOMPATIBLE;
420 
421 			nummodes++;
422 		}
423 NextMode:
424 		pmodenums++;
425 	}
426 
427 // add the VESA modes at the start of the mode list (if there are any)
428 	if (nummodes)
429 	{
430 		vesa_modes[nummodes-1].pnext = pvidmodes;
431 		pvidmodes = &vesa_modes[0];
432 		numvidmodes += nummodes;
433 		ppal = dos_getmemory(256*4);
434 	}
435 
436 	dos_freememory(pinfoblock);
437 }
438 
439 
440 /*
441 ================
442 VID_ExtraGetModeInfo
443 ================
444 */
VID_ExtraGetModeInfo(int modenum)445 qboolean VID_ExtraGetModeInfo(int modenum)
446 {
447 	char	*infobuf;
448 	int		numimagepages;
449 
450 	infobuf = dos_getmemory(256);
451 
452 	regs.x.ax = 0x4f01;
453 	regs.x.cx = modenum;
454 	regs.x.es = ptr2real(infobuf) >> 4;
455 	regs.x.di = ptr2real(infobuf) & 0xf;
456 	dos_int86(0x10);
457 	if (regs.x.ax != 0x4f)
458 	{
459 		return false;
460 	}
461 	else
462 	{
463 		modeinfo.modenum = modenum;
464 		modeinfo.bits_per_pixel = *(char*)(infobuf+25);
465 		modeinfo.bytes_per_pixel = (modeinfo.bits_per_pixel+1)/8;
466 		modeinfo.width = *(short*)(infobuf+18);
467 		modeinfo.height = *(short*)(infobuf+20);
468 
469 	// we do only 8-bpp in software
470 		if ((modeinfo.bits_per_pixel != 8) ||
471 			(modeinfo.bytes_per_pixel != 1) ||
472 			(modeinfo.width > MAXWIDTH) ||
473 			(modeinfo.height > MAXHEIGHT))
474 		{
475 			return false;
476 		}
477 
478 		modeinfo.mode_attributes = *(short*)infobuf;
479 
480 	// we only want color graphics modes that are supported by the hardware
481 		if ((modeinfo.mode_attributes &
482 			 (MODE_SUPPORTED_IN_HW | COLOR_MODE | GRAPHICS_MODE)) !=
483 			(MODE_SUPPORTED_IN_HW | COLOR_MODE | GRAPHICS_MODE))
484 		{
485 			return false;
486 		}
487 
488 	// we only work with linear frame buffers, except for 320x200, which can
489 	// effectively be linear when banked at 0xA000
490 		if (!(modeinfo.mode_attributes & LINEAR_FRAME_BUFFER))
491 		{
492 			if ((modeinfo.width != 320) || (modeinfo.height != 200))
493 				return false;
494 		}
495 
496 		modeinfo.bytes_per_scanline = *(short*)(infobuf+16);
497 
498 		modeinfo.pagesize = modeinfo.bytes_per_scanline * modeinfo.height;
499 
500 		if (modeinfo.pagesize > totalvidmem)
501 			return false;
502 
503 	// force to one page if the adapter reports it doesn't support more pages
504 	// than that, no matter how much memory it has--it may not have hardware
505 	// support for page flipping
506 		numimagepages = *(unsigned char *)(infobuf+29);
507 
508 		if (numimagepages <= 0)
509 		{
510 		// wrong, but there seems to be an ATI VESA driver that reports 0
511 			modeinfo.numpages = 1;
512 		}
513 		else if (numimagepages < 3)
514 		{
515 			modeinfo.numpages = numimagepages;
516 		}
517 		else
518 		{
519 			modeinfo.numpages = 3;
520 		}
521 
522 		if (*(char*)(infobuf+2) & 5)
523 		{
524 			modeinfo.winasegment = *(unsigned short*)(infobuf+8);
525 			modeinfo.win = 0;
526 		}
527 		else if (*(char*)(infobuf+3) & 5)
528 		{
529 			modeinfo.winbsegment = *(unsigned short*)(infobuf+8);
530 			modeinfo.win = 1;
531 		}
532 		modeinfo.granularity = *(short*)(infobuf+4) * 1024;
533 		modeinfo.win_size = *(short*)(infobuf+6) * 1024;
534 		modeinfo.bits_per_pixel = *(char*)(infobuf+25);
535 		modeinfo.bytes_per_pixel = (modeinfo.bits_per_pixel+1)/8;
536 		modeinfo.memory_model = *(unsigned char*)(infobuf+27);
537 		modeinfo.num_pages = *(char*)(infobuf+29) + 1;
538 
539 		modeinfo.red_width = *(char*)(infobuf+31);
540 		modeinfo.red_pos = *(char*)(infobuf+32);
541 		modeinfo.green_width = *(char*)(infobuf+33);
542 		modeinfo.green_pos = *(char*)(infobuf+34);
543 		modeinfo.blue_width = *(char*)(infobuf+35);
544 		modeinfo.blue_pos = *(char*)(infobuf+36);
545 
546 		modeinfo.pptr = *(long *)(infobuf+40);
547 
548 #if 0
549 		printf("VID: (VESA) info for mode 0x%x\n", modeinfo.modenum);
550 		printf("  mode attrib = 0x%0x\n", modeinfo.mode_attributes);
551 		printf("  win a attrib = 0x%0x\n", *(unsigned char*)(infobuf+2));
552 		printf("  win b attrib = 0x%0x\n", *(unsigned char*)(infobuf+3));
553 		printf("  win a seg 0x%0x\n", (int) modeinfo.winasegment);
554 		printf("  win b seg 0x%0x\n", (int) modeinfo.winbsegment);
555 		printf("  bytes per scanline = %d\n",
556 				modeinfo.bytes_per_scanline);
557 		printf("  width = %d, height = %d\n", modeinfo.width,
558 				modeinfo.height);
559 		printf("  win = %c\n", 'A' + modeinfo.win);
560 		printf("  win granularity = %d\n", modeinfo.granularity);
561 		printf("  win size = %d\n", modeinfo.win_size);
562 		printf("  bits per pixel = %d\n", modeinfo.bits_per_pixel);
563 		printf("  bytes per pixel = %d\n", modeinfo.bytes_per_pixel);
564 		printf("  memory model = 0x%x\n", modeinfo.memory_model);
565 		printf("  num pages = %d\n", modeinfo.num_pages);
566 		printf("  red width = %d\n", modeinfo.red_width);
567 		printf("  red pos = %d\n", modeinfo.red_pos);
568 		printf("  green width = %d\n", modeinfo.green_width);
569 		printf("  green pos = %d\n", modeinfo.green_pos);
570 		printf("  blue width = %d\n", modeinfo.blue_width);
571 		printf("  blue pos = %d\n", modeinfo.blue_pos);
572 		printf("  phys mem = %x\n", modeinfo.pptr);
573 #endif
574 	}
575 
576 	dos_freememory(infobuf);
577 
578 	return true;
579 }
580 
581 
582 /*
583 ================
584 VID_ExtraInitMode
585 ================
586 */
VID_ExtraInitMode(viddef_t * lvid,vmode_t * pcurrentmode)587 int VID_ExtraInitMode (viddef_t *lvid, vmode_t *pcurrentmode)
588 {
589 	vesa_extra_t	*pextra;
590 	int				pageoffset;
591 
592 	pextra = pcurrentmode->pextradata;
593 
594 	if (vid_nopageflip.value)
595 		lvid->numpages = 1;
596 	else
597 		lvid->numpages = pcurrentmode->numpages;
598 
599 // clean up any old vid buffer lying around, alloc new if needed
600 	if (!VGA_FreeAndAllocVidbuffer (lvid, lvid->numpages == 1))
601 		return -1;	// memory alloc failed
602 
603 // clear the screen and wait for the next frame. VGA_pcurmode, which
604 // VGA_ClearVideoMem relies on, is guaranteed to be set because mode 0 is
605 // always the first mode set in a session
606 	if (VGA_pcurmode)
607 		VGA_ClearVideoMem (VGA_pcurmode->planar);
608 
609 // set the mode
610 	regs.x.ax = 0x4f02;
611 	regs.x.bx = pextra->vesamode;
612 	dos_int86(0x10);
613 
614 	if (regs.x.ax != 0x4f)
615 		return 0;
616 
617 	VID_banked = !(pextra->vesamode & LINEAR_MODE);
618 	VID_membase = pextra->plinearmem;
619 	VGA_width = lvid->width;
620 	VGA_height = lvid->height;
621 	VGA_rowbytes = lvid->rowbytes;
622 
623 	lvid->colormap = host_colormap;
624 
625 	VID_pagelist = &pextra->pages[0];
626 
627 // wait for display enable by default only when triple-buffering on a VGA-
628 // compatible machine that actually has a functioning display enable status
629 	vsync_exists = VID_ExtraStateFound (0x08);
630 	de_exists = VID_ExtraStateFound (0x01);
631 
632 	if (!pextra->vga_incompatible  &&
633 		(lvid->numpages == 3)      &&
634 		de_exists                  &&
635 		(_vid_wait_override.value == 0.0))
636 	{
637 		Cvar_SetValue ("vid_wait", (float)VID_WAIT_DISPLAY_ENABLE);
638 
639 		VID_displayedpage = 0;
640 		VID_currentpage = 1;
641 	}
642 	else
643 	{
644 		if ((lvid->numpages == 1) && (_vid_wait_override.value == 0.0))
645 		{
646 			Cvar_SetValue ("vid_wait", (float)VID_WAIT_NONE);
647 			VID_displayedpage = VID_currentpage = 0;
648 		}
649 		else
650 		{
651 			Cvar_SetValue ("vid_wait", (float)VID_WAIT_VSYNC);
652 
653 			VID_displayedpage = 0;
654 
655 			if (lvid->numpages > 1)
656 				VID_currentpage = 1;
657 			else
658 				VID_currentpage = 0;
659 		}
660 	}
661 
662 // TODO: really should be a call to a function
663 	pageoffset = VID_pagelist[VID_displayedpage];
664 
665 	regs.x.ax = 0x4f07;
666 	regs.x.bx = 0x80;	// wait for vsync so we know page 0 is visible
667 	regs.x.cx = pageoffset % VGA_rowbytes;
668 	regs.x.dx = pageoffset / VGA_rowbytes;
669 	dos_int86(0x10);
670 
671 	if (VID_banked)
672 	{
673 		regs.x.ax = 0x4f05;
674 		regs.x.bx = 0;
675 		regs.x.dx = VID_currentpage;
676 		dos_int86(0x10);
677 
678 		VGA_pagebase = VID_membase;
679 	}
680 	else
681 	{
682 		VGA_pagebase = VID_membase + VID_pagelist[VID_currentpage];
683 	}
684 
685 	if (lvid->numpages > 1)
686 	{
687 		lvid->buffer = VGA_pagebase;
688 		lvid->conbuffer = lvid->buffer;
689 	}
690 	else
691 	{
692 		lvid->rowbytes = lvid->width;
693 	}
694 
695 	lvid->direct = VGA_pagebase;
696 	lvid->conrowbytes = lvid->rowbytes;
697 	lvid->conwidth = lvid->width;
698 	lvid->conheight = lvid->height;
699 
700 	lvid->maxwarpwidth = WARP_WIDTH;
701 	lvid->maxwarpheight = WARP_HEIGHT;
702 
703 	VGA_pcurmode = pcurrentmode;
704 
705 	D_InitCaches (vid_surfcache, vid_surfcachesize);
706 
707 	return 1;
708 }
709 
710 
711 /*
712 ================
713 VID_ExtraSwapBuffers
714 ================
715 */
VID_ExtraSwapBuffers(viddef_t * lvid,vmode_t * pcurrentmode,vrect_t * rects)716 void VID_ExtraSwapBuffers (viddef_t *lvid, vmode_t *pcurrentmode,
717 	vrect_t *rects)
718 {
719 	int	pageoffset;
720 
721 	UNUSED(rects);
722 	UNUSED(pcurrentmode);
723 
724 	pageoffset = VID_pagelist[VID_currentpage];
725 
726 // display the newly finished page
727 	if (lvid->numpages > 1)
728 	{
729 	// page flipped
730 		regs.x.ax = 0x4f07;
731 
732 		if (vid_wait.value != VID_WAIT_VSYNC)
733 		{
734 			if ((vid_wait.value == VID_WAIT_DISPLAY_ENABLE) && de_exists)
735 				VID_ExtraWaitDisplayEnable ();
736 
737 			regs.x.bx = VESA_DONT_WAIT_VSYNC;
738 		}
739 		else
740 		{
741 			regs.x.bx = VESA_WAIT_VSYNC;	// double buffered has to wait
742 		}
743 
744 		regs.x.cx = pageoffset % VGA_rowbytes;
745 		regs.x.dx = pageoffset / VGA_rowbytes;
746 		dos_int86(0x10);
747 
748 		VID_displayedpage = VID_currentpage;
749 		if (++VID_currentpage >= lvid->numpages)
750 			VID_currentpage = 0;
751 
752 	//
753 	// set the new write window if this is a banked mode; otherwise, set the
754 	// new address to which to write
755 	//
756 		if (VID_banked)
757 		{
758 			regs.x.ax = 0x4f05;
759 			regs.x.bx = 0;
760 			regs.x.dx = VID_currentpage;
761 			dos_int86(0x10);
762 		}
763 		else
764 		{
765 			lvid->direct = lvid->buffer;	// direct drawing goes to the
766 											//  currently displayed page
767 			lvid->buffer = VID_membase + VID_pagelist[VID_currentpage];
768 			lvid->conbuffer = lvid->buffer;
769 		}
770 
771 		VGA_pagebase = lvid->buffer;
772 	}
773 	else
774 	{
775 	// non-page-flipped
776 		if (vsync_exists && (vid_wait.value == VID_WAIT_VSYNC))
777 		{
778 			VGA_WaitVsync ();
779 		}
780 
781 		while (rects)
782 		{
783 			VGA_UpdateLinearScreen (
784 					lvid->buffer + rects->x + (rects->y * lvid->rowbytes),
785 		 			VGA_pagebase + rects->x + (rects->y * VGA_rowbytes),
786 					rects->width,
787 					rects->height,
788 					lvid->rowbytes,
789 					VGA_rowbytes);
790 
791 			rects = rects->pnext;
792 		}
793 	}
794 }
795 
796