vid_ext.c 19 KB

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