1999-12-25 05:32:39 +00:00
|
|
|
/*
|
2000-03-24 14:43:43 +00:00
|
|
|
vid_ext.c
|
1999-12-25 05:32:39 +00:00
|
|
|
|
2000-03-24 14:43:43 +00:00
|
|
|
extended video modes, VESA-specific DOS video stuff
|
1999-12-25 05:32:39 +00:00
|
|
|
|
2000-03-24 14:43:43 +00:00
|
|
|
Copyright (C) 1996-1997 Id Software, Inc.
|
|
|
|
Copyright (C) 1999,2000 contributors of the QuakeForge project
|
|
|
|
Please see the file "AUTHORS" for a list of contributors
|
1999-12-25 05:32:39 +00:00
|
|
|
|
2000-03-24 14:43:43 +00:00
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
of the License, or (at your option) any later version.
|
1999-12-25 05:32:39 +00:00
|
|
|
|
2000-03-24 14:43:43 +00:00
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
1999-12-25 05:32:39 +00:00
|
|
|
|
2000-03-24 14:43:43 +00:00
|
|
|
See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to:
|
|
|
|
|
|
|
|
Free Software Foundation, Inc.
|
|
|
|
59 Temple Place - Suite 330
|
|
|
|
Boston, MA 02111-1307, USA
|
|
|
|
|
|
|
|
$Id$
|
1999-12-25 05:32:39 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
// TODO: make dependencies on vid_vga.c explicit or eliminate them
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <dos.h>
|
|
|
|
|
2000-03-24 14:43:43 +00:00
|
|
|
#include <quakedef.h>
|
|
|
|
#include <d_local.h>
|
|
|
|
#include <dosisms.h>
|
|
|
|
#include <vid_dos.h>
|
1999-12-25 05:32:39 +00:00
|
|
|
#include <dpmi.h>
|
2000-08-18 04:30:22 +00:00
|
|
|
#include <sys.h>
|
|
|
|
#include <console.h>
|
1999-12-25 05:32:39 +00:00
|
|
|
|
|
|
|
#define MODE_SUPPORTED_IN_HW 0x0001
|
2000-08-10 12:16:59 +00:00
|
|
|
#define COLOR_MODE 0x0008
|
|
|
|
#define GRAPHICS_MODE 0x0010
|
|
|
|
#define VGA_INCOMPATIBLE 0x0020
|
|
|
|
#define LINEAR_FRAME_BUFFER 0x0080
|
1999-12-25 05:32:39 +00:00
|
|
|
|
2000-08-10 12:16:59 +00:00
|
|
|
#define LINEAR_MODE 0x4000
|
1999-12-25 05:32:39 +00:00
|
|
|
|
|
|
|
#define VESA_DONT_WAIT_VSYNC 0 // when page flipping
|
2000-08-10 12:16:59 +00:00
|
|
|
#define VESA_WAIT_VSYNC 0x80
|
1999-12-25 05:32:39 +00:00
|
|
|
|
2000-08-10 12:16:59 +00:00
|
|
|
#define MAX_VESA_MODES 30 // we'll just take the first 30 if there
|
2000-08-20 13:33:48 +00:00
|
|
|
// are more
|
1999-12-25 05:32:39 +00:00
|
|
|
typedef struct {
|
2000-08-10 12:16:59 +00:00
|
|
|
int pages[3]; // either 2 or 3 is valid
|
|
|
|
int vesamode; // LINEAR_MODE set if linear mode
|
1999-12-25 05:32:39 +00:00
|
|
|
void *plinearmem; // linear address of start of frame buffer
|
|
|
|
qboolean vga_incompatible;
|
|
|
|
} vesa_extra_t;
|
|
|
|
|
|
|
|
static vmode_t vesa_modes[MAX_VESA_MODES] =
|
|
|
|
{{NULL, NULL, " ********* VESA modes ********* "}};
|
|
|
|
static vesa_extra_t vesa_extra[MAX_VESA_MODES];
|
2000-08-10 12:16:59 +00:00
|
|
|
static char names[MAX_VESA_MODES][10];
|
1999-12-25 05:32:39 +00:00
|
|
|
|
2000-08-10 12:16:59 +00:00
|
|
|
extern regs_t regs;
|
1999-12-25 05:32:39 +00:00
|
|
|
|
2000-08-10 12:16:59 +00:00
|
|
|
static int VID_currentpage;
|
|
|
|
static int VID_displayedpage;
|
|
|
|
static int *VID_pagelist;
|
|
|
|
static byte *VID_membase;
|
|
|
|
static int VID_banked;
|
1999-12-25 05:32:39 +00:00
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
2000-08-10 12:16:59 +00:00
|
|
|
int modenum;
|
|
|
|
int mode_attributes;
|
1999-12-25 05:32:39 +00:00
|
|
|
int winasegment;
|
|
|
|
int winbsegment;
|
2000-08-10 12:16:59 +00:00
|
|
|
int bytes_per_scanline; // bytes per logical scanline (+16)
|
|
|
|
int win; // window number (A=0, B=1)
|
|
|
|
int win_size; // window size (+6)
|
|
|
|
int granularity; // how finely i can set the window in vid mem (+4)
|
|
|
|
int width, height; // displayed width and height (+18, +20)
|
|
|
|
int bits_per_pixel; // er, better be 8, 15, 16, 24, or 32 (+25)
|
|
|
|
int bytes_per_pixel; // er, better be 1, 2, or 4
|
|
|
|
int memory_model; // and better be 4 or 6, packed or direct color (+27)
|
|
|
|
int num_pages; // number of complete frame buffer pages (+29)
|
|
|
|
int red_width; // the # of bits in the red component (+31)
|
|
|
|
int red_pos; // the bit position of the red component (+32)
|
|
|
|
int green_width; // etc.. (+33)
|
|
|
|
int green_pos; // (+34)
|
|
|
|
int blue_width; // (+35)
|
|
|
|
int blue_pos; // (+36)
|
|
|
|
int pptr;
|
1999-12-25 05:32:39 +00:00
|
|
|
int pagesize;
|
|
|
|
int numpages;
|
|
|
|
} modeinfo_t;
|
|
|
|
|
2000-08-10 12:16:59 +00:00
|
|
|
static modeinfo_t modeinfo;
|
1999-12-25 05:32:39 +00:00
|
|
|
|
|
|
|
// all bytes to avoid problems with compiler field packing
|
|
|
|
typedef struct vbeinfoblock_s {
|
2000-08-10 12:16:59 +00:00
|
|
|
byte VbeSignature[4];
|
|
|
|
byte VbeVersion[2];
|
|
|
|
byte OemStringPtr[4];
|
|
|
|
byte Capabilities[4];
|
|
|
|
byte VideoModePtr[4];
|
|
|
|
byte TotalMemory[2];
|
|
|
|
byte OemSoftwareRev[2];
|
|
|
|
byte OemVendorNamePtr[4];
|
|
|
|
byte OemProductNamePtr[4];
|
|
|
|
byte OemProductRevPtr[4];
|
|
|
|
byte Reserved[222];
|
|
|
|
byte OemData[256];
|
1999-12-25 05:32:39 +00:00
|
|
|
} vbeinfoblock_t;
|
|
|
|
|
|
|
|
static int totalvidmem;
|
|
|
|
static byte *ppal;
|
|
|
|
qboolean vsync_exists, de_exists;
|
|
|
|
|
|
|
|
qboolean VID_ExtraGetModeInfo(int modenum);
|
|
|
|
int VID_ExtraInitMode (viddef_t *vid, vmode_t *pcurrentmode);
|
|
|
|
void VID_ExtraSwapBuffers (viddef_t *vid, vmode_t *pcurrentmode,
|
|
|
|
vrect_t *rects);
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
VGA_BankedBeginDirectRect
|
|
|
|
================
|
|
|
|
*/
|
2000-08-20 13:33:48 +00:00
|
|
|
void
|
|
|
|
VGA_BankedBeginDirectRect ( viddef_t *lvid, struct vmode_s *pcurrentmode,
|
|
|
|
int x, int y, byte *pbitmap, int width, int height )
|
1999-12-25 05:32:39 +00:00
|
|
|
{
|
|
|
|
if (!lvid->direct)
|
|
|
|
return;
|
|
|
|
|
|
|
|
regs.x.ax = 0x4f05;
|
|
|
|
regs.x.bx = 0;
|
|
|
|
regs.x.dx = VID_displayedpage;
|
|
|
|
dos_int86(0x10);
|
|
|
|
|
|
|
|
VGA_BeginDirectRect (lvid, pcurrentmode, x, y, pbitmap, width, height);
|
|
|
|
|
|
|
|
regs.x.ax = 0x4f05;
|
|
|
|
regs.x.bx = 0;
|
|
|
|
regs.x.dx = VID_currentpage;
|
|
|
|
dos_int86(0x10);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
VGA_BankedEndDirectRect
|
|
|
|
================
|
|
|
|
*/
|
2000-08-20 13:33:48 +00:00
|
|
|
void
|
|
|
|
VGA_BankedEndDirectRect ( viddef_t *lvid, struct vmode_s *pcurrentmode,
|
|
|
|
int x, int y, int width, int height )
|
1999-12-25 05:32:39 +00:00
|
|
|
{
|
|
|
|
if (!lvid->direct)
|
|
|
|
return;
|
|
|
|
|
|
|
|
regs.x.ax = 0x4f05;
|
|
|
|
regs.x.bx = 0;
|
|
|
|
regs.x.dx = VID_displayedpage;
|
|
|
|
dos_int86(0x10);
|
|
|
|
|
|
|
|
VGA_EndDirectRect (lvid, pcurrentmode, x, y, width, height);
|
|
|
|
|
|
|
|
regs.x.ax = 0x4f05;
|
|
|
|
regs.x.bx = 0;
|
|
|
|
regs.x.dx = VID_currentpage;
|
|
|
|
dos_int86(0x10);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
VID_SetVESAPalette
|
|
|
|
================
|
|
|
|
*/
|
2000-08-20 13:33:48 +00:00
|
|
|
void
|
|
|
|
VID_SetVESAPalette ( viddef_t *lvid, vmode_t *pcurrentmode,
|
|
|
|
unsigned char *pal )
|
1999-12-25 05:32:39 +00:00
|
|
|
{
|
2000-08-10 12:16:59 +00:00
|
|
|
int i;
|
1999-12-25 05:32:39 +00:00
|
|
|
byte *pp;
|
|
|
|
|
|
|
|
UNUSED(lvid);
|
|
|
|
UNUSED(pcurrentmode);
|
|
|
|
|
|
|
|
pp = ppal;
|
|
|
|
|
|
|
|
for (i=0 ; i<256 ; i++)
|
|
|
|
{
|
|
|
|
pp[2] = pal[0] >> 2;
|
|
|
|
pp[1] = pal[1] >> 2;
|
|
|
|
pp[0] = pal[2] >> 2;
|
|
|
|
pp += 4;
|
|
|
|
pal += 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
regs.x.ax = 0x4F09;
|
|
|
|
regs.x.bx = 0;
|
|
|
|
regs.x.cx = 256;
|
|
|
|
regs.x.dx = 0;
|
|
|
|
regs.x.es = ptr2real(ppal) >> 4;
|
|
|
|
regs.x.di = ptr2real(ppal) & 0xf;
|
|
|
|
dos_int86(0x10);
|
|
|
|
|
|
|
|
if (regs.x.ax != 0x4f)
|
|
|
|
Sys_Error ("Unable to load VESA palette\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
VID_ExtraFarToLinear
|
|
|
|
================
|
|
|
|
*/
|
2000-08-20 13:33:48 +00:00
|
|
|
void *
|
|
|
|
VID_ExtraFarToLinear ( void *ptr )
|
1999-12-25 05:32:39 +00:00
|
|
|
{
|
2000-08-10 12:16:59 +00:00
|
|
|
int temp;
|
1999-12-25 05:32:39 +00:00
|
|
|
|
|
|
|
temp = (int)ptr;
|
|
|
|
return real2ptr(((temp & 0xFFFF0000) >> 12) + (temp & 0xFFFF));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
VID_ExtraWaitDisplayEnable
|
|
|
|
================
|
|
|
|
*/
|
2000-08-20 13:33:48 +00:00
|
|
|
void
|
|
|
|
VID_ExtraWaitDisplayEnable ( void )
|
1999-12-25 05:32:39 +00:00
|
|
|
{
|
|
|
|
while ((inportb (0x3DA) & 0x01) == 1)
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
VID_ExtraVidLookForState
|
|
|
|
================
|
|
|
|
*/
|
2000-08-20 13:33:48 +00:00
|
|
|
qboolean
|
|
|
|
VID_ExtraVidLookForState ( unsigned state, unsigned mask )
|
1999-12-25 05:32:39 +00:00
|
|
|
{
|
2000-08-10 12:16:59 +00:00
|
|
|
int i;
|
1999-12-25 05:32:39 +00:00
|
|
|
double starttime, time;
|
|
|
|
|
2000-01-07 01:16:26 +00:00
|
|
|
starttime = Sys_DoubleTime ();
|
1999-12-25 05:32:39 +00:00
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
for (i=0 ; i<100000 ; i++)
|
|
|
|
{
|
|
|
|
if ((inportb (0x3DA) & mask) == state)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2000-01-07 01:16:26 +00:00
|
|
|
time = Sys_DoubleTime ();
|
1999-12-25 05:32:39 +00:00
|
|
|
} while ((time - starttime) < 0.1);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
VID_ExtraStateFound
|
|
|
|
================
|
|
|
|
*/
|
2000-08-20 13:33:48 +00:00
|
|
|
qboolean
|
|
|
|
VID_ExtraStateFound ( unsigned state )
|
1999-12-25 05:32:39 +00:00
|
|
|
{
|
2000-08-10 12:16:59 +00:00
|
|
|
int i, workingstate;
|
1999-12-25 05:32:39 +00:00
|
|
|
|
|
|
|
workingstate = 0;
|
|
|
|
|
|
|
|
for (i=0 ; i<10 ; i++)
|
|
|
|
{
|
|
|
|
if (!VID_ExtraVidLookForState(workingstate, state))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
workingstate ^= state;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
VID_InitExtra
|
|
|
|
================
|
|
|
|
*/
|
2000-08-20 13:33:48 +00:00
|
|
|
void
|
|
|
|
VID_InitExtra ( void )
|
1999-12-25 05:32:39 +00:00
|
|
|
{
|
2000-08-10 12:16:59 +00:00
|
|
|
int nummodes;
|
|
|
|
short *pmodenums;
|
1999-12-25 05:32:39 +00:00
|
|
|
vbeinfoblock_t *pinfoblock;
|
|
|
|
__dpmi_meminfo phys_mem_info;
|
|
|
|
|
|
|
|
pinfoblock = dos_getmemory(sizeof(vbeinfoblock_t));
|
|
|
|
|
|
|
|
*(long *)pinfoblock->VbeSignature = 'V' + ('B'<<8) + ('E'<<16) + ('2'<<24);
|
|
|
|
|
|
|
|
// see if VESA support is available
|
|
|
|
regs.x.ax = 0x4f00;
|
|
|
|
regs.x.es = ptr2real(pinfoblock) >> 4;
|
|
|
|
regs.x.di = ptr2real(pinfoblock) & 0xf;
|
|
|
|
dos_int86(0x10);
|
|
|
|
|
|
|
|
if (regs.x.ax != 0x4f)
|
|
|
|
return; // no VESA support
|
|
|
|
|
|
|
|
if (pinfoblock->VbeVersion[1] < 0x02)
|
|
|
|
return; // not VESA 2.0 or greater
|
|
|
|
|
|
|
|
Con_Printf ("VESA 2.0 compliant adapter:\n%s\n",
|
2000-08-18 04:30:22 +00:00
|
|
|
(char *) VID_ExtraFarToLinear (*(byte **)&pinfoblock->OemStringPtr[0]));
|
1999-12-25 05:32:39 +00:00
|
|
|
|
|
|
|
totalvidmem = *(unsigned short *)&pinfoblock->TotalMemory[0] << 16;
|
|
|
|
|
|
|
|
pmodenums = (short *)
|
|
|
|
VID_ExtraFarToLinear (*(byte **)&pinfoblock->VideoModePtr[0]);
|
|
|
|
|
|
|
|
// find 8 bit modes until we either run out of space or run out of modes
|
|
|
|
nummodes = 0;
|
|
|
|
|
|
|
|
while ((*pmodenums != -1) && (nummodes < MAX_VESA_MODES))
|
|
|
|
{
|
|
|
|
if (VID_ExtraGetModeInfo (*pmodenums))
|
|
|
|
{
|
|
|
|
vesa_modes[nummodes].pnext = &vesa_modes[nummodes+1];
|
|
|
|
if (modeinfo.width > 999)
|
|
|
|
{
|
|
|
|
if (modeinfo.height > 999)
|
|
|
|
{
|
2000-01-05 00:11:02 +00:00
|
|
|
sprintf(&names[nummodes][0], "%4dx%4d", modeinfo.width,
|
1999-12-25 05:32:39 +00:00
|
|
|
modeinfo.height);
|
|
|
|
names[nummodes][9] = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2000-01-05 00:11:02 +00:00
|
|
|
sprintf(&names[nummodes][0], "%4dx%3d", modeinfo.width,
|
1999-12-25 05:32:39 +00:00
|
|
|
modeinfo.height);
|
|
|
|
names[nummodes][8] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (modeinfo.height > 999)
|
|
|
|
{
|
2000-01-05 00:11:02 +00:00
|
|
|
sprintf(&names[nummodes][0], "%3dx%4d", modeinfo.width,
|
1999-12-25 05:32:39 +00:00
|
|
|
modeinfo.height);
|
|
|
|
names[nummodes][8] = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2000-01-05 00:11:02 +00:00
|
|
|
sprintf(&names[nummodes][0], "%3dx%3d", modeinfo.width,
|
1999-12-25 05:32:39 +00:00
|
|
|
modeinfo.height);
|
|
|
|
names[nummodes][7] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
vesa_modes[nummodes].name = &names[nummodes][0];
|
|
|
|
vesa_modes[nummodes].width = modeinfo.width;
|
|
|
|
vesa_modes[nummodes].height = modeinfo.height;
|
|
|
|
vesa_modes[nummodes].aspect =
|
|
|
|
((float)modeinfo.height / (float)modeinfo.width) *
|
|
|
|
(320.0 / 240.0);
|
|
|
|
vesa_modes[nummodes].rowbytes = modeinfo.bytes_per_scanline;
|
|
|
|
vesa_modes[nummodes].planar = 0;
|
|
|
|
vesa_modes[nummodes].pextradata = &vesa_extra[nummodes];
|
|
|
|
vesa_modes[nummodes].setmode = VID_ExtraInitMode;
|
|
|
|
vesa_modes[nummodes].swapbuffers = VID_ExtraSwapBuffers;
|
|
|
|
vesa_modes[nummodes].setpalette = VID_SetVESAPalette;
|
|
|
|
|
|
|
|
if (modeinfo.mode_attributes & LINEAR_FRAME_BUFFER)
|
|
|
|
{
|
|
|
|
// add linear bit to mode for linear modes
|
|
|
|
vesa_extra[nummodes].vesamode = modeinfo.modenum | LINEAR_MODE;
|
|
|
|
vesa_extra[nummodes].pages[0] = 0;
|
|
|
|
vesa_extra[nummodes].pages[1] = modeinfo.pagesize;
|
|
|
|
vesa_extra[nummodes].pages[2] = modeinfo.pagesize * 2;
|
|
|
|
vesa_modes[nummodes].numpages = modeinfo.numpages;
|
|
|
|
|
|
|
|
vesa_modes[nummodes].begindirectrect = VGA_BeginDirectRect;
|
|
|
|
vesa_modes[nummodes].enddirectrect = VGA_EndDirectRect;
|
|
|
|
|
|
|
|
phys_mem_info.address = (int)modeinfo.pptr;
|
|
|
|
phys_mem_info.size = 0x400000;
|
|
|
|
|
|
|
|
if (__dpmi_physical_address_mapping(&phys_mem_info))
|
|
|
|
goto NextMode;
|
|
|
|
|
|
|
|
vesa_extra[nummodes].plinearmem =
|
|
|
|
real2ptr (phys_mem_info.address);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// banked at 0xA0000
|
|
|
|
vesa_extra[nummodes].vesamode = modeinfo.modenum;
|
|
|
|
vesa_extra[nummodes].pages[0] = 0;
|
|
|
|
vesa_extra[nummodes].plinearmem =
|
|
|
|
real2ptr(modeinfo.winasegment<<4);
|
|
|
|
|
|
|
|
vesa_modes[nummodes].begindirectrect =
|
|
|
|
VGA_BankedBeginDirectRect;
|
|
|
|
vesa_modes[nummodes].enddirectrect = VGA_BankedEndDirectRect;
|
|
|
|
vesa_extra[nummodes].pages[1] = modeinfo.pagesize;
|
|
|
|
vesa_extra[nummodes].pages[2] = modeinfo.pagesize * 2;
|
|
|
|
vesa_modes[nummodes].numpages = modeinfo.numpages;
|
|
|
|
}
|
|
|
|
|
|
|
|
vesa_extra[nummodes].vga_incompatible =
|
|
|
|
modeinfo.mode_attributes & VGA_INCOMPATIBLE;
|
|
|
|
|
|
|
|
nummodes++;
|
|
|
|
}
|
|
|
|
NextMode:
|
|
|
|
pmodenums++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// add the VESA modes at the start of the mode list (if there are any)
|
|
|
|
if (nummodes)
|
|
|
|
{
|
|
|
|
vesa_modes[nummodes-1].pnext = pvidmodes;
|
|
|
|
pvidmodes = &vesa_modes[0];
|
|
|
|
numvidmodes += nummodes;
|
|
|
|
ppal = dos_getmemory(256*4);
|
|
|
|
}
|
|
|
|
|
|
|
|
dos_freememory(pinfoblock);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
VID_ExtraGetModeInfo
|
|
|
|
================
|
|
|
|
*/
|
2000-08-20 13:33:48 +00:00
|
|
|
qboolean
|
|
|
|
VID_ExtraGetModeInfo ( int modenum )
|
1999-12-25 05:32:39 +00:00
|
|
|
{
|
|
|
|
char *infobuf;
|
2000-08-10 12:16:59 +00:00
|
|
|
int numimagepages;
|
1999-12-25 05:32:39 +00:00
|
|
|
|
|
|
|
infobuf = dos_getmemory(256);
|
|
|
|
|
|
|
|
regs.x.ax = 0x4f01;
|
|
|
|
regs.x.cx = modenum;
|
|
|
|
regs.x.es = ptr2real(infobuf) >> 4;
|
|
|
|
regs.x.di = ptr2real(infobuf) & 0xf;
|
|
|
|
dos_int86(0x10);
|
|
|
|
if (regs.x.ax != 0x4f)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
modeinfo.modenum = modenum;
|
|
|
|
modeinfo.bits_per_pixel = *(char*)(infobuf+25);
|
|
|
|
modeinfo.bytes_per_pixel = (modeinfo.bits_per_pixel+1)/8;
|
|
|
|
modeinfo.width = *(short*)(infobuf+18);
|
|
|
|
modeinfo.height = *(short*)(infobuf+20);
|
|
|
|
|
|
|
|
// we do only 8-bpp in software
|
|
|
|
if ((modeinfo.bits_per_pixel != 8) ||
|
|
|
|
(modeinfo.bytes_per_pixel != 1) ||
|
|
|
|
(modeinfo.width > MAXWIDTH) ||
|
|
|
|
(modeinfo.height > MAXHEIGHT))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
modeinfo.mode_attributes = *(short*)infobuf;
|
|
|
|
|
|
|
|
// we only want color graphics modes that are supported by the hardware
|
|
|
|
if ((modeinfo.mode_attributes &
|
|
|
|
(MODE_SUPPORTED_IN_HW | COLOR_MODE | GRAPHICS_MODE)) !=
|
|
|
|
(MODE_SUPPORTED_IN_HW | COLOR_MODE | GRAPHICS_MODE))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// we only work with linear frame buffers, except for 320x200, which can
|
|
|
|
// effectively be linear when banked at 0xA000
|
|
|
|
if (!(modeinfo.mode_attributes & LINEAR_FRAME_BUFFER))
|
|
|
|
{
|
|
|
|
if ((modeinfo.width != 320) || (modeinfo.height != 200))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
modeinfo.bytes_per_scanline = *(short*)(infobuf+16);
|
|
|
|
|
|
|
|
modeinfo.pagesize = modeinfo.bytes_per_scanline * modeinfo.height;
|
|
|
|
|
|
|
|
if (modeinfo.pagesize > totalvidmem)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// force to one page if the adapter reports it doesn't support more pages
|
|
|
|
// than that, no matter how much memory it has--it may not have hardware
|
|
|
|
// support for page flipping
|
|
|
|
numimagepages = *(unsigned char *)(infobuf+29);
|
|
|
|
|
|
|
|
if (numimagepages <= 0)
|
|
|
|
{
|
|
|
|
// wrong, but there seems to be an ATI VESA driver that reports 0
|
|
|
|
modeinfo.numpages = 1;
|
|
|
|
}
|
|
|
|
else if (numimagepages < 3)
|
|
|
|
{
|
|
|
|
modeinfo.numpages = numimagepages;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
modeinfo.numpages = 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*(char*)(infobuf+2) & 5)
|
|
|
|
{
|
|
|
|
modeinfo.winasegment = *(unsigned short*)(infobuf+8);
|
|
|
|
modeinfo.win = 0;
|
|
|
|
}
|
|
|
|
else if (*(char*)(infobuf+3) & 5)
|
|
|
|
{
|
|
|
|
modeinfo.winbsegment = *(unsigned short*)(infobuf+8);
|
|
|
|
modeinfo.win = 1;
|
|
|
|
}
|
|
|
|
modeinfo.granularity = *(short*)(infobuf+4) * 1024;
|
|
|
|
modeinfo.win_size = *(short*)(infobuf+6) * 1024;
|
|
|
|
modeinfo.bits_per_pixel = *(char*)(infobuf+25);
|
|
|
|
modeinfo.bytes_per_pixel = (modeinfo.bits_per_pixel+1)/8;
|
|
|
|
modeinfo.memory_model = *(unsigned char*)(infobuf+27);
|
|
|
|
modeinfo.num_pages = *(char*)(infobuf+29) + 1;
|
|
|
|
|
|
|
|
modeinfo.red_width = *(char*)(infobuf+31);
|
|
|
|
modeinfo.red_pos = *(char*)(infobuf+32);
|
|
|
|
modeinfo.green_width = *(char*)(infobuf+33);
|
|
|
|
modeinfo.green_pos = *(char*)(infobuf+34);
|
|
|
|
modeinfo.blue_width = *(char*)(infobuf+35);
|
|
|
|
modeinfo.blue_pos = *(char*)(infobuf+36);
|
|
|
|
|
|
|
|
modeinfo.pptr = *(long *)(infobuf+40);
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
printf("VID: (VESA) info for mode 0x%x\n", modeinfo.modenum);
|
|
|
|
printf(" mode attrib = 0x%0x\n", modeinfo.mode_attributes);
|
|
|
|
printf(" win a attrib = 0x%0x\n", *(unsigned char*)(infobuf+2));
|
|
|
|
printf(" win b attrib = 0x%0x\n", *(unsigned char*)(infobuf+3));
|
|
|
|
printf(" win a seg 0x%0x\n", (int) modeinfo.winasegment);
|
|
|
|
printf(" win b seg 0x%0x\n", (int) modeinfo.winbsegment);
|
2000-08-10 12:16:59 +00:00
|
|
|
printf(" bytes per scanline = %i\n",
|
1999-12-25 05:32:39 +00:00
|
|
|
modeinfo.bytes_per_scanline);
|
2000-08-10 12:16:59 +00:00
|
|
|
printf(" width = %i, height = %i\n", modeinfo.width,
|
1999-12-25 05:32:39 +00:00
|
|
|
modeinfo.height);
|
|
|
|
printf(" win = %c\n", 'A' + modeinfo.win);
|
2000-08-10 12:16:59 +00:00
|
|
|
printf(" win granularity = %i\n", modeinfo.granularity);
|
|
|
|
printf(" win size = %i\n", modeinfo.win_size);
|
|
|
|
printf(" bits per pixel = %i\n", modeinfo.bits_per_pixel);
|
|
|
|
printf(" bytes per pixel = %i\n", modeinfo.bytes_per_pixel);
|
1999-12-25 05:32:39 +00:00
|
|
|
printf(" memory model = 0x%x\n", modeinfo.memory_model);
|
2000-08-10 12:16:59 +00:00
|
|
|
printf(" num pages = %i\n", modeinfo.num_pages);
|
|
|
|
printf(" red width = %i\n", modeinfo.red_width);
|
|
|
|
printf(" red pos = %i\n", modeinfo.red_pos);
|
|
|
|
printf(" green width = %i\n", modeinfo.green_width);
|
|
|
|
printf(" green pos = %i\n", modeinfo.green_pos);
|
|
|
|
printf(" blue width = %i\n", modeinfo.blue_width);
|
|
|
|
printf(" blue pos = %i\n", modeinfo.blue_pos);
|
1999-12-25 05:32:39 +00:00
|
|
|
printf(" phys mem = %x\n", modeinfo.pptr);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
dos_freememory(infobuf);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
VID_ExtraInitMode
|
|
|
|
================
|
|
|
|
*/
|
2000-08-20 13:33:48 +00:00
|
|
|
int
|
|
|
|
VID_ExtraInitMode ( viddef_t *lvid, vmode_t *pcurrentmode )
|
1999-12-25 05:32:39 +00:00
|
|
|
{
|
|
|
|
vesa_extra_t *pextra;
|
2000-08-10 12:16:59 +00:00
|
|
|
int pageoffset;
|
1999-12-25 05:32:39 +00:00
|
|
|
|
|
|
|
pextra = pcurrentmode->pextradata;
|
|
|
|
|
2000-02-27 07:13:32 +00:00
|
|
|
if (vid_nopageflip->value)
|
1999-12-25 05:32:39 +00:00
|
|
|
lvid->numpages = 1;
|
|
|
|
else
|
|
|
|
lvid->numpages = pcurrentmode->numpages;
|
|
|
|
|
|
|
|
// clean up any old vid buffer lying around, alloc new if needed
|
|
|
|
if (!VGA_FreeAndAllocVidbuffer (lvid, lvid->numpages == 1))
|
|
|
|
return -1; // memory alloc failed
|
|
|
|
|
|
|
|
// clear the screen and wait for the next frame. VGA_pcurmode, which
|
|
|
|
// VGA_ClearVideoMem relies on, is guaranteed to be set because mode 0 is
|
|
|
|
// always the first mode set in a session
|
|
|
|
if (VGA_pcurmode)
|
|
|
|
VGA_ClearVideoMem (VGA_pcurmode->planar);
|
|
|
|
|
|
|
|
// set the mode
|
|
|
|
regs.x.ax = 0x4f02;
|
|
|
|
regs.x.bx = pextra->vesamode;
|
|
|
|
dos_int86(0x10);
|
|
|
|
|
|
|
|
if (regs.x.ax != 0x4f)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
VID_banked = !(pextra->vesamode & LINEAR_MODE);
|
|
|
|
VID_membase = pextra->plinearmem;
|
|
|
|
VGA_width = lvid->width;
|
|
|
|
VGA_height = lvid->height;
|
|
|
|
VGA_rowbytes = lvid->rowbytes;
|
|
|
|
|
|
|
|
lvid->colormap = host_colormap;
|
|
|
|
|
|
|
|
VID_pagelist = &pextra->pages[0];
|
|
|
|
|
|
|
|
// wait for display enable by default only when triple-buffering on a VGA-
|
|
|
|
// compatible machine that actually has a functioning display enable status
|
|
|
|
vsync_exists = VID_ExtraStateFound (0x08);
|
|
|
|
de_exists = VID_ExtraStateFound (0x01);
|
|
|
|
|
2000-08-10 12:16:59 +00:00
|
|
|
if (!pextra->vga_incompatible
|
|
|
|
&& (lvid->numpages == 3)
|
|
|
|
&& de_exists
|
|
|
|
&& (_vid_wait_override->value == 0.0))
|
1999-12-25 05:32:39 +00:00
|
|
|
{
|
2000-02-28 01:52:08 +00:00
|
|
|
vid_wait->value = (float)VID_WAIT_DISPLAY_ENABLE;
|
1999-12-25 05:32:39 +00:00
|
|
|
|
|
|
|
VID_displayedpage = 0;
|
|
|
|
VID_currentpage = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2000-02-27 07:13:32 +00:00
|
|
|
if ((lvid->numpages == 1) && (_vid_wait_override->value == 0.0))
|
1999-12-25 05:32:39 +00:00
|
|
|
{
|
2000-02-28 01:52:08 +00:00
|
|
|
vid_wait->value = (float)VID_WAIT_NONE;
|
1999-12-25 05:32:39 +00:00
|
|
|
VID_displayedpage = VID_currentpage = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2000-02-28 01:52:08 +00:00
|
|
|
vid_wait->value = (float)VID_WAIT_VSYNC;
|
1999-12-25 05:32:39 +00:00
|
|
|
|
|
|
|
VID_displayedpage = 0;
|
|
|
|
|
|
|
|
if (lvid->numpages > 1)
|
|
|
|
VID_currentpage = 1;
|
|
|
|
else
|
|
|
|
VID_currentpage = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: really should be a call to a function
|
|
|
|
pageoffset = VID_pagelist[VID_displayedpage];
|
|
|
|
|
|
|
|
regs.x.ax = 0x4f07;
|
|
|
|
regs.x.bx = 0x80; // wait for vsync so we know page 0 is visible
|
|
|
|
regs.x.cx = pageoffset % VGA_rowbytes;
|
|
|
|
regs.x.dx = pageoffset / VGA_rowbytes;
|
|
|
|
dos_int86(0x10);
|
|
|
|
|
|
|
|
if (VID_banked)
|
|
|
|
{
|
|
|
|
regs.x.ax = 0x4f05;
|
|
|
|
regs.x.bx = 0;
|
|
|
|
regs.x.dx = VID_currentpage;
|
|
|
|
dos_int86(0x10);
|
|
|
|
|
|
|
|
VGA_pagebase = VID_membase;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
VGA_pagebase = VID_membase + VID_pagelist[VID_currentpage];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lvid->numpages > 1)
|
|
|
|
{
|
|
|
|
lvid->buffer = VGA_pagebase;
|
|
|
|
lvid->conbuffer = lvid->buffer;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
lvid->rowbytes = lvid->width;
|
|
|
|
}
|
|
|
|
|
|
|
|
lvid->direct = VGA_pagebase;
|
|
|
|
lvid->conrowbytes = lvid->rowbytes;
|
|
|
|
lvid->conwidth = lvid->width;
|
|
|
|
lvid->conheight = lvid->height;
|
|
|
|
|
|
|
|
lvid->maxwarpwidth = WARP_WIDTH;
|
|
|
|
lvid->maxwarpheight = WARP_HEIGHT;
|
|
|
|
|
|
|
|
VGA_pcurmode = pcurrentmode;
|
|
|
|
|
|
|
|
D_InitCaches (vid_surfcache, vid_surfcachesize);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
VID_ExtraSwapBuffers
|
|
|
|
================
|
|
|
|
*/
|
2000-08-20 13:33:48 +00:00
|
|
|
void
|
|
|
|
VID_ExtraSwapBuffers ( viddef_t *lvid, vmode_t *pcurrentmode,
|
|
|
|
vrect_t *rects )
|
1999-12-25 05:32:39 +00:00
|
|
|
{
|
|
|
|
int pageoffset;
|
|
|
|
|
|
|
|
UNUSED(rects);
|
|
|
|
UNUSED(pcurrentmode);
|
|
|
|
|
|
|
|
pageoffset = VID_pagelist[VID_currentpage];
|
|
|
|
|
|
|
|
// display the newly finished page
|
|
|
|
if (lvid->numpages > 1)
|
|
|
|
{
|
|
|
|
// page flipped
|
|
|
|
regs.x.ax = 0x4f07;
|
2000-03-19 15:59:51 +00:00
|
|
|
|
2000-02-27 07:13:32 +00:00
|
|
|
if (vid_wait->value != VID_WAIT_VSYNC)
|
1999-12-25 05:32:39 +00:00
|
|
|
{
|
2000-02-27 07:13:32 +00:00
|
|
|
if ((vid_wait->value == VID_WAIT_DISPLAY_ENABLE) && de_exists)
|
1999-12-25 05:32:39 +00:00
|
|
|
VID_ExtraWaitDisplayEnable ();
|
2000-03-19 15:59:51 +00:00
|
|
|
|
1999-12-25 05:32:39 +00:00
|
|
|
regs.x.bx = VESA_DONT_WAIT_VSYNC;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
regs.x.bx = VESA_WAIT_VSYNC; // double buffered has to wait
|
|
|
|
}
|
|
|
|
|
|
|
|
regs.x.cx = pageoffset % VGA_rowbytes;
|
|
|
|
regs.x.dx = pageoffset / VGA_rowbytes;
|
|
|
|
dos_int86(0x10);
|
2000-03-19 15:59:51 +00:00
|
|
|
|
1999-12-25 05:32:39 +00:00
|
|
|
VID_displayedpage = VID_currentpage;
|
|
|
|
if (++VID_currentpage >= lvid->numpages)
|
|
|
|
VID_currentpage = 0;
|
2000-03-19 15:59:51 +00:00
|
|
|
|
1999-12-25 05:32:39 +00:00
|
|
|
//
|
|
|
|
// set the new write window if this is a banked mode; otherwise, set the
|
|
|
|
// new address to which to write
|
|
|
|
//
|
|
|
|
if (VID_banked)
|
|
|
|
{
|
|
|
|
regs.x.ax = 0x4f05;
|
|
|
|
regs.x.bx = 0;
|
|
|
|
regs.x.dx = VID_currentpage;
|
|
|
|
dos_int86(0x10);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
lvid->direct = lvid->buffer; // direct drawing goes to the
|
2000-08-20 13:33:48 +00:00
|
|
|
// currently displayed page
|
1999-12-25 05:32:39 +00:00
|
|
|
lvid->buffer = VID_membase + VID_pagelist[VID_currentpage];
|
|
|
|
lvid->conbuffer = lvid->buffer;
|
|
|
|
}
|
2000-03-19 15:59:51 +00:00
|
|
|
|
1999-12-25 05:32:39 +00:00
|
|
|
VGA_pagebase = lvid->buffer;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// non-page-flipped
|
2000-02-27 07:13:32 +00:00
|
|
|
if (vsync_exists && (vid_wait->value == VID_WAIT_VSYNC))
|
1999-12-25 05:32:39 +00:00
|
|
|
{
|
|
|
|
VGA_WaitVsync ();
|
|
|
|
}
|
|
|
|
|
|
|
|
while (rects)
|
|
|
|
{
|
|
|
|
VGA_UpdateLinearScreen (
|
|
|
|
lvid->buffer + rects->x + (rects->y * lvid->rowbytes),
|
|
|
|
VGA_pagebase + rects->x + (rects->y * VGA_rowbytes),
|
|
|
|
rects->width,
|
|
|
|
rects->height,
|
|
|
|
lvid->rowbytes,
|
|
|
|
VGA_rowbytes);
|
|
|
|
|
|
|
|
rects = rects->pnext;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-08-18 04:30:22 +00:00
|
|
|
#if 0
|
2000-08-20 13:33:48 +00:00
|
|
|
int
|
|
|
|
VID_ExtraOptionDraw ( unsigned int options_draw_cursor )
|
2000-08-10 12:16:59 +00:00
|
|
|
{
|
|
|
|
int drawn;
|
|
|
|
|
|
|
|
drawn = 0;
|
|
|
|
|
|
|
|
/* Port specific Options menu entries */
|
|
|
|
#if 0
|
|
|
|
M_Print (16, options_draw_cursor+=8, " Dummy");
|
|
|
|
M_DrawCheckbox (220, options_draw_cursor, dummy->value);
|
|
|
|
drawn++;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return drawn; // return number of drawn menu entries
|
|
|
|
}
|
|
|
|
|
2000-08-20 13:33:48 +00:00
|
|
|
void
|
|
|
|
VID_ExtraOptionCmd ( int option_cursor, int dir )
|
2000-08-10 12:16:59 +00:00
|
|
|
{
|
|
|
|
/* dir: -1 = LEFT, 0 = ENTER, 1 = RIGHT */
|
|
|
|
#if 0
|
|
|
|
switch(option_cursor) {
|
|
|
|
case 0: // Always start with 0
|
|
|
|
dummy->value = !dummy->value;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2000-08-20 13:33:48 +00:00
|
|
|
void
|
|
|
|
VID_InitCvars ( void )
|
2000-08-10 12:16:59 +00:00
|
|
|
{
|
|
|
|
// It may not look like it, but this is important
|
|
|
|
}
|
2000-03-31 23:58:53 +00:00
|
|
|
|
2000-08-20 13:33:48 +00:00
|
|
|
void
|
|
|
|
VID_LockBuffer ( void )
|
2000-08-10 12:16:59 +00:00
|
|
|
{
|
|
|
|
}
|
2000-03-31 23:58:53 +00:00
|
|
|
|
2000-08-20 13:33:48 +00:00
|
|
|
void
|
|
|
|
VID_UnlockBuffer ( void )
|
2000-08-10 12:16:59 +00:00
|
|
|
{
|
|
|
|
}
|
2000-08-18 04:30:22 +00:00
|
|
|
#endif
|