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