Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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_vga.c: VGA-specific DOS video stuff
  22. //
  23.  
  24. // TODO: proper handling of page-swap failure
  25.  
  26. #include <dos.h>
  27.  
  28. #include "quakedef.h"
  29. #include "d_local.h"
  30. #include "dosisms.h"
  31. #include "vid_dos.h"
  32. #include <dpmi.h>
  33.  
  34. extern regs_t regs;
  35.  
  36. int             VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes;
  37. byte    *VGA_pagebase;
  38. vmode_t *VGA_pcurmode;
  39.  
  40. static int              VGA_planar;
  41. static int              VGA_numpages;
  42. static int              VGA_buffersize;
  43.  
  44. void    *vid_surfcache;
  45. int             vid_surfcachesize;
  46.  
  47. int             VGA_highhunkmark;
  48.  
  49. #include "vgamodes.h"
  50.  
  51. #define NUMVIDMODES             (sizeof(vgavidmodes) / sizeof(vgavidmodes[0]))
  52.  
  53. void VGA_UpdatePlanarScreen (void *srcbuffer);
  54.  
  55. static byte     backingbuf[48*24];
  56.  
  57. /*
  58. ================
  59. VGA_BeginDirectRect
  60. ================
  61. */
  62. void VGA_BeginDirectRect (viddef_t *lvid, struct vmode_s *pcurrentmode, int x,
  63.         int y, byte *pbitmap, int width, int height)
  64. {
  65.         int             i, j, k, plane, reps, repshift;
  66.  
  67.         if (!lvid->direct)
  68.                 return;
  69.  
  70.         if (lvid->aspect > 1.5)
  71.         {
  72.                 reps = 2;
  73.                 repshift = 1;
  74.         }
  75.         else
  76.         {
  77.                 reps = 1;
  78.                 repshift = 0;
  79.         }
  80.  
  81.         if (pcurrentmode->planar)
  82.         {
  83.                 for (plane=0 ; plane<4 ; plane++)
  84.                 {
  85.                 // select the correct plane for reading and writing
  86.                         outportb (SC_INDEX, MAP_MASK);
  87.                         outportb (SC_DATA, 1 << plane);
  88.                         outportb (GC_INDEX, READ_MAP);
  89.                         outportb (GC_DATA, plane);
  90.  
  91.                         for (i=0 ; i<(height << repshift) ; i += reps)
  92.                         {
  93.                                 for (k=0 ; k<reps ; k++)
  94.                                 {
  95.                                         for (j=0 ; j<(width >> 2) ; j++)
  96.                                         {
  97.                                                 backingbuf[(i + k) * 24 + (j << 2) + plane] =
  98.                                                                 lvid->direct[(y + i + k) * VGA_rowbytes +
  99.                                                                 (x >> 2) + j];
  100.                                                 lvid->direct[(y + i + k) * VGA_rowbytes + (x>>2) + j] =
  101.                                                                 pbitmap[(i >> repshift) * 24 +
  102.                                                                 (j << 2) + plane];
  103.                                         }
  104.                                 }
  105.                         }
  106.                 }
  107.         }
  108.         else
  109.         {
  110.                 for (i=0 ; i<(height << repshift) ; i += reps)
  111.                 {
  112.                         for (j=0 ; j<reps ; j++)
  113.                         {
  114.                                 memcpy (&backingbuf[(i + j) * 24],
  115.                                                 lvid->direct + x + ((y << repshift) + i + j) *
  116.                                                  VGA_rowbytes,
  117.                                                 width);
  118.                                 memcpy (lvid->direct + x + ((y << repshift) + i + j) *
  119.                                                  VGA_rowbytes,
  120.                                                 &pbitmap[(i >> repshift) * width],
  121.                                                 width);
  122.                         }
  123.                 }
  124.         }
  125. }
  126.  
  127.  
  128. /*
  129. ================
  130. VGA_EndDirectRect
  131. ================
  132. */
  133. void VGA_EndDirectRect (viddef_t *lvid, struct vmode_s *pcurrentmode, int x,
  134.         int y, int width, int height)
  135. {
  136.         int             i, j, k, plane, reps, repshift;
  137.  
  138.         if (!lvid->direct)
  139.                 return;
  140.  
  141.         if (lvid->aspect > 1.5)
  142.         {
  143.                 reps = 2;
  144.                 repshift = 1;
  145.         }
  146.         else
  147.         {
  148.                 reps = 1;
  149.                 repshift = 0;
  150.         }
  151.  
  152.         if (pcurrentmode->planar)
  153.         {
  154.                 for (plane=0 ; plane<4 ; plane++)
  155.                 {
  156.                 // select the correct plane for writing
  157.                         outportb (SC_INDEX, MAP_MASK);
  158.                         outportb (SC_DATA, 1 << plane);
  159.  
  160.                         for (i=0 ; i<(height << repshift) ; i += reps)
  161.                         {
  162.                                 for (k=0 ; k<reps ; k++)
  163.                                 {
  164.                                         for (j=0 ; j<(width >> 2) ; j++)
  165.                                         {
  166.                                                 lvid->direct[(y + i + k) * VGA_rowbytes + (x>>2) + j] =
  167.                                                                 backingbuf[(i + k) * 24 + (j << 2) + plane];
  168.                                         }
  169.                                 }
  170.                         }
  171.                 }
  172.         }
  173.         else
  174.         {
  175.                 for (i=0 ; i<(height << repshift) ; i += reps)
  176.                 {
  177.                         for (j=0 ; j<reps ; j++)
  178.                         {
  179.                                 memcpy (lvid->direct + x + ((y << repshift) + i + j) *
  180.                                                  VGA_rowbytes,
  181.                                                 &backingbuf[(i + j) * 24],
  182.                                                 width);
  183.                         }
  184.                 }
  185.         }
  186. }
  187.  
  188.  
  189. /*
  190. ================
  191. VGA_Init
  192. ================
  193. */
  194. void VGA_Init (void)
  195. {
  196.         int             i;
  197.  
  198. // link together all the VGA modes
  199.         for (i=0 ; i<(NUMVIDMODES - 1) ; i++)
  200.         {
  201.                 vgavidmodes[i].pnext = &vgavidmodes[i+1];
  202.         }
  203.  
  204. // add the VGA modes at the start of the mode list
  205.         vgavidmodes[NUMVIDMODES-1].pnext = pvidmodes;
  206.         pvidmodes = &vgavidmodes[0];
  207.  
  208.         numvidmodes += NUMVIDMODES;
  209. }
  210.  
  211.  
  212. /*
  213. ================
  214. VGA_WaitVsync
  215. ================
  216. */
  217. void VGA_WaitVsync (void)
  218. {
  219.         while ((inportb (0x3DA) & 0x08) == 0)
  220.                 ;
  221. }
  222.  
  223.  
  224. /*
  225. ================
  226. VGA_ClearVideoMem
  227. ================
  228. */
  229. void VGA_ClearVideoMem (int planar)
  230. {
  231.  
  232.         if (planar)
  233.         {
  234.         // enable all planes for writing
  235.                 outportb (SC_INDEX, MAP_MASK);
  236.                 outportb (SC_DATA, 0x0F);
  237.         }
  238.  
  239.         Q_memset (VGA_pagebase, 0, VGA_rowbytes * VGA_height);
  240. }
  241.  
  242. /*
  243. ================
  244. VGA_FreeAndAllocVidbuffer
  245. ================
  246. */
  247. qboolean VGA_FreeAndAllocVidbuffer (viddef_t *lvid, int allocnewbuffer)
  248. {
  249.         int             tsize, tbuffersize;
  250.  
  251.         if (allocnewbuffer)
  252.         {
  253.         // alloc an extra line in case we want to wrap, and allocate the z-buffer
  254.                 tbuffersize = (lvid->rowbytes * (lvid->height + 1)) +
  255.                                 (lvid->width * lvid->height * sizeof (*d_pzbuffer));
  256.         }
  257.         else
  258.         {
  259.         // just allocate the z-buffer
  260.                 tbuffersize = lvid->width * lvid->height * sizeof (*d_pzbuffer);
  261.         }
  262.  
  263.         tsize = D_SurfaceCacheForRes (lvid->width, lvid->height);
  264.  
  265.         tbuffersize += tsize;
  266.  
  267. // see if there's enough memory, allowing for the normal mode 0x13 pixel,
  268. // z, and surface buffers
  269.         if ((host_parms.memsize - tbuffersize + SURFCACHE_SIZE_AT_320X200 +
  270.                  0x10000 * 3) < minimum_memory)
  271.         {
  272.                 Con_Printf ("Not enough memory for video mode\n");
  273.                 VGA_pcurmode = NULL;    // so no further accesses to the buffer are
  274.                                                                 //  attempted, particularly when clearing
  275.                 return false;           // not enough memory for mode
  276.         }
  277.  
  278.         VGA_buffersize = tbuffersize;
  279.         vid_surfcachesize = tsize;
  280.  
  281.         if (d_pzbuffer)
  282.         {
  283.                 D_FlushCaches ();
  284.                 Hunk_FreeToHighMark (VGA_highhunkmark);
  285.                 d_pzbuffer = NULL;
  286.         }
  287.  
  288.         VGA_highhunkmark = Hunk_HighMark ();
  289.  
  290.         d_pzbuffer = Hunk_HighAllocName (VGA_buffersize, "video");
  291.  
  292.         vid_surfcache = (byte *)d_pzbuffer
  293.                 + lvid->width * lvid->height * sizeof (*d_pzbuffer);
  294.        
  295.         if (allocnewbuffer)
  296.         {
  297.                 lvid->buffer = (void *)( (byte *)vid_surfcache + vid_surfcachesize);
  298.                 lvid->conbuffer = lvid->buffer;
  299.         }
  300.  
  301.         return true;
  302. }
  303.  
  304.  
  305. /*
  306. ================
  307. VGA_CheckAdequateMem
  308. ================
  309. */
  310. qboolean VGA_CheckAdequateMem (int width, int height, int rowbytes,
  311.         int allocnewbuffer)
  312. {
  313.         int             tbuffersize;
  314.  
  315.         tbuffersize = width * height * sizeof (*d_pzbuffer);
  316.  
  317.         if (allocnewbuffer)
  318.         {
  319.         // alloc an extra line in case we want to wrap, and allocate the z-buffer
  320.                 tbuffersize += (rowbytes * (height + 1));
  321.         }
  322.  
  323.         tbuffersize += D_SurfaceCacheForRes (width, height);
  324.  
  325. // see if there's enough memory, allowing for the normal mode 0x13 pixel,
  326. // z, and surface buffers
  327.         if ((host_parms.memsize - tbuffersize + SURFCACHE_SIZE_AT_320X200 +
  328.                  0x10000 * 3) < minimum_memory)
  329.         {
  330.                 return false;           // not enough memory for mode
  331.         }
  332.  
  333.         return true;
  334. }
  335.  
  336.  
  337. /*
  338. ================
  339. VGA_InitMode
  340. ================
  341. */
  342. int VGA_InitMode (viddef_t *lvid, vmode_t *pcurrentmode)
  343. {
  344.         vextra_t                *pextra;
  345.  
  346.         pextra = pcurrentmode->pextradata;
  347.  
  348.         if (!VGA_FreeAndAllocVidbuffer (lvid, pextra->vidbuffer))
  349.                 return -1;      // memory alloc failed
  350.  
  351.         if (VGA_pcurmode)
  352.                 VGA_ClearVideoMem (VGA_pcurmode->planar);
  353.  
  354. // mode 0x13 is the base for all the Mode X-class mode sets
  355.         regs.h.ah = 0;
  356.         regs.h.al = 0x13;
  357.         dos_int86(0x10);
  358.  
  359.         VGA_pagebase = (void *)real2ptr(0xa0000);
  360.         lvid->direct = (pixel_t *)VGA_pagebase;
  361.  
  362. // set additional registers as needed
  363.         VideoRegisterSet (pextra->pregset);
  364.  
  365.         VGA_numpages = 1;
  366.         lvid->numpages = VGA_numpages;
  367.  
  368.         VGA_width = (lvid->width + 0x1F) & ~0x1F;
  369.         VGA_height = lvid->height;
  370.         VGA_planar = pcurrentmode->planar;
  371.         if (VGA_planar)
  372.                 VGA_rowbytes = lvid->rowbytes / 4;
  373.         else
  374.                 VGA_rowbytes = lvid->rowbytes;
  375.         VGA_bufferrowbytes = lvid->rowbytes;
  376.         lvid->colormap = host_colormap;
  377.         lvid->fullbright = 256 - LittleLong (*((int *)lvid->colormap + 2048));
  378.  
  379.         lvid->maxwarpwidth = WARP_WIDTH;
  380.         lvid->maxwarpheight = WARP_HEIGHT;
  381.  
  382.         lvid->conbuffer = lvid->buffer;
  383.         lvid->conrowbytes = lvid->rowbytes;
  384.         lvid->conwidth = lvid->width;
  385.         lvid->conheight = lvid->height;
  386.  
  387.         VGA_pcurmode = pcurrentmode;
  388.  
  389.         VGA_ClearVideoMem (pcurrentmode->planar);
  390.  
  391.         if (_vid_wait_override.value)
  392.         {
  393.                 Cvar_SetValue ("vid_wait", (float)VID_WAIT_VSYNC);
  394.         }
  395.         else
  396.         {
  397.                 Cvar_SetValue ("vid_wait", (float)VID_WAIT_NONE);
  398.         }
  399.  
  400.         D_InitCaches (vid_surfcache, vid_surfcachesize);
  401.  
  402.         return 1;
  403. }
  404.  
  405.  
  406. /*
  407. ================
  408. VGA_SetPalette
  409. ================
  410. */
  411. void VGA_SetPalette(viddef_t *lvid, vmode_t *pcurrentmode, unsigned char *pal)
  412. {
  413.         int shiftcomponents=2;
  414.         int i;
  415.  
  416.         UNUSED(lvid);
  417.         UNUSED(pcurrentmode);
  418.  
  419.         dos_outportb(0x3c8, 0);
  420.         for (i=0 ; i<768 ; i++)
  421.                 outportb(0x3c9, pal[i]>>shiftcomponents);
  422. }
  423.  
  424.  
  425. /*
  426. ================
  427. VGA_SwapBuffersCopy
  428. ================
  429. */
  430. void VGA_SwapBuffersCopy (viddef_t *lvid, vmode_t *pcurrentmode,
  431.         vrect_t *rects)
  432. {
  433.  
  434.         UNUSED(pcurrentmode);
  435.  
  436. // TODO: can write a dword at a time
  437. // TODO: put in ASM
  438. // TODO: copy only specified rectangles
  439.         if (VGA_planar)
  440.         {
  441.  
  442.         // TODO: copy only specified rectangles
  443.  
  444.                 VGA_UpdatePlanarScreen (lvid->buffer);
  445.         }
  446.         else
  447.         {
  448.                 while (rects)
  449.                 {
  450.                         VGA_UpdateLinearScreen (
  451.                                         lvid->buffer + rects->x + (rects->y * lvid->rowbytes),
  452.                                         VGA_pagebase + rects->x + (rects->y * VGA_rowbytes),
  453.                                         rects->width,
  454.                                         rects->height,
  455.                                         lvid->rowbytes,
  456.                                         VGA_rowbytes);
  457.  
  458.                         rects = rects->pnext;
  459.                 }
  460.         }
  461. }
  462.  
  463.  
  464. /*
  465. ================
  466. VGA_SwapBuffers
  467. ================
  468. */
  469. void VGA_SwapBuffers (viddef_t *lvid, vmode_t *pcurrentmode, vrect_t *rects)
  470. {
  471.         UNUSED(lvid);
  472.  
  473.         if (vid_wait.value == VID_WAIT_VSYNC)
  474.                 VGA_WaitVsync ();
  475.  
  476.         VGA_SwapBuffersCopy (lvid, pcurrentmode, rects);
  477. }
  478.  
  479.