|
|
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.