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