Home | History | Annotate | Download | only in WinQuake
      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 */
    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 */
    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 */
    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 */
    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 */
    234 void VID_ExtraWaitDisplayEnable ()
    235 {
    236 	while ((inportb (0x3DA) & 0x01) == 1)
    237 		;
    238 }
    239 
    240 
    241 /*
    242 ================
    243 VID_ExtraVidLookForState
    244 ================
    245 */
    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 */
    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 */
    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 */
    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 */
    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 */
    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