home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 113 / EnigmaAmiga113CD.iso / software / sviluppo / quake_src / vid_ext.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-17  |  19.7 KB  |  796 lines

  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.