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