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