2423 lines
74 KiB
C
2423 lines
74 KiB
C
/* Copyright 1998 (c) by Salvador Eduardo Tropea
|
|
This code is part of the FreeBE/AF project you can use it under the
|
|
terms and conditions of the FreeBE/AF project. */
|
|
/*
|
|
E-mail: salvador@inti.gov.ar, set-soft@usa.net, set@computer.org
|
|
*/
|
|
/* Note: Currently it means: you can use it for any purpose. But if the
|
|
project changes it could change so check the FreeBE/AF readmes.
|
|
Additionally: if anybody uses part of this code please let me know to add
|
|
it to my curriculum. */
|
|
/*****************************************************************************
|
|
|
|
Implemented:
|
|
|
|
SetMix, Set8x8MonoPattern, Set8x8ColorPattern, Use8x8ColorPattern
|
|
DrawLine, SetLineStipple, SetLineStippleCount, DrawStippleLine
|
|
DrawRect, DrawScan, DrawPattRect, DrawPattScan, DrawColorPattRect
|
|
DrawColorPattScan
|
|
BitBlt, SrcTransBlt
|
|
SetCursor, SetCursorPos, SetCursorColor (*), ShowCursor
|
|
SetBank, SetBank32, SetPaletteData, GetDisplayStartStatus (*2)
|
|
SetDisplayStart, SetActiveBuffer, SetVisibleBuffer
|
|
GetVideoModeInfo, SetVideoMode, WaitTillIdle, SetupDriver, InitDriver
|
|
RestoreTextMode, EnableDirectAccess, DisableDirectAccess,
|
|
GetClosestPixelClock
|
|
BitBltSys, SrcTransBltSys, PutMonoImage
|
|
DrawScanList, DrawPattScanList, DrawColorPattScanList
|
|
DrawTrap (*3)
|
|
|
|
From Inertia: (Old functions conditionally included because seems they won't
|
|
be used)
|
|
|
|
GetConfigInfo,GetCurrentMode,SetVSyncWidth,GetVSyncWidth,GetBank,
|
|
GetVisibleBuffer,GetDisplayStart,SetDisplayStartAddr,IsVSync,WaitVSync,
|
|
GetActiveBuffer,IsIdle
|
|
|
|
(*) See implementation notes
|
|
(*2) Dummy because looks like TGUI doesn't set the interrupt flag.
|
|
(*3) Implemented using scans because isn't supported by the hard.
|
|
|
|
The following are not supported by 9440:
|
|
|
|
Implementation notes:
|
|
|
|
* TGUI9440 doesn't support acelerations in 24 bpp, I must check if the
|
|
cursor works.
|
|
* TGUI9440 doesn't support Background Mix, as I think the only routine that
|
|
needs it is DrawPattRect (and your equivalent Scan) I did a trick:
|
|
a) When fore and back mix are the same (most of the time) I ignore back mix.
|
|
b) When back mix is "No Operation" (Destination) I use a transparent mode.
|
|
c) When both are important I use 2 steps, first makes a transparent blit
|
|
with the fore mix, and the second uses an inverted patterned and is done
|
|
using the back mix as fore mix.
|
|
I hope that is better than soft fills.
|
|
* The cursor uses color index 0 for the main color and color index 0xFF for
|
|
the xor area. I think it could be very annoying in 8bpp modes perhaps I must
|
|
disable the cursor on these modes.
|
|
* Supported video modes:
|
|
8 bpp 15 bpp 16 bpp 24 bpp
|
|
320x200 * * * *
|
|
320x240 * * * *
|
|
400x300 * * * *
|
|
512x384 * * * *
|
|
576x432 * * * *
|
|
640x400 * * * *
|
|
640x480 * * * *
|
|
720x540 * * * *
|
|
800x600 * * * *
|
|
900x675 * * * *
|
|
1024x768 * * * (1)
|
|
|
|
(1) Needs more than 2Mb so is impossible with 9440
|
|
|
|
*****************************************************************************/
|
|
|
|
/* Define it if you don't want to call WaitTillIdle, I doubt somebody could
|
|
really want it */
|
|
//#define WAITTILLIDLE_NOT_NEEDED
|
|
|
|
#include "mytypes.h"
|
|
#include "setmode.h"
|
|
#include "tgui.h"
|
|
#include "vbeaf.h"
|
|
#include "vga.h"
|
|
#include <pc.h>
|
|
#define VBE_AF_INCLUDED
|
|
|
|
#define NULL 0
|
|
|
|
#define TEST_MODE_INTERNAL
|
|
//#define X11Cursor
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
void SetBank32( );
|
|
void SetBank32End( );
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
void WaitTillIdle(AF_DRIVER *af);
|
|
|
|
uchar ROPEquiv[32] = {
|
|
ROP_P, /* 0x00: AF_REPLACE_MIX => Source */
|
|
ROP_PaD, /* 0x01: AF_AND_MIX => And */
|
|
ROP_PoD, /* 0x02: AF_OR_MIX => Or */
|
|
ROP_PxD, /* 0x03: AF_XOR_MIX => XOr */
|
|
ROP_D, /* 0x04: AF_NOP_MIX => Destination */
|
|
ROP_D, ROP_D, ROP_D, ROP_D, ROP_D, ROP_D, ROP_D, ROP_D, ROP_D, ROP_D, ROP_D,
|
|
/* Pattern operation as defined by Windows
|
|
Note: Pat is pen (color) for line drawing */
|
|
ROP_0, /* 0x10: AF_R2_BLACK => 0 */
|
|
ROP_n_PoD, /* 0x11: AF_R2_NOTMERGESRC => NOr Pat */
|
|
ROP_nPaD, /* 0x12: AF_R2_MASKNOTSRC => !Pat & Dest */
|
|
ROP_nP, /* 0x13: AF_R2_NOTCOPYSRC => !Pat */
|
|
ROP_PanD, /* 0x14: AF_R2_MASKSRCNOT => Pat & !Dest */
|
|
ROP_nD, /* 0x15: AF_R2_NOT => !Dest */
|
|
ROP_PxD, /* 0x16: AF_R2_XORSRC => XOr Pat*/
|
|
ROP_n_PaD, /* 0x17: AF_R2_NOTMASKSRC => NAnd Pat */
|
|
ROP_PaD, /* 0x18: AF_R2_MASKSRC => And Pat */
|
|
ROP_n_PxD, /* 0x19: AF_R2_NOTXORSRC => XNOr Pat */
|
|
ROP_D, /* 0x1A: AF_R2_NOP => Dest */
|
|
ROP_nPoD, /* 0x1B: AF_R2_MERGENOTSRC => !Pat | Dest */
|
|
ROP_P, /* 0x1C: AF_R2_COPYSRC => Pat */
|
|
ROP_PonD, /* 0x1D: AF_R2_MERGESRCNOT => Pat | !Dest */
|
|
ROP_PoD, /* 0x1E: AF_R2_MERGESRC => Or Pat */
|
|
ROP_1 /* 0x1F: AF_R2_WHITE => 1 */
|
|
};
|
|
|
|
uchar ROPImageEquiv[32] = {
|
|
ROP_S, /* 0x00: AF_REPLACE_MIX => Source */
|
|
ROP_SaD, /* 0x01: AF_AND_MIX => And */
|
|
ROP_SoD, /* 0x02: AF_OR_MIX => Or */
|
|
ROP_SxD, /* 0x03: AF_XOR_MIX => XOr */
|
|
ROP_D, /* 0x04: AF_NOP_MIX => Destination */
|
|
ROP_D, ROP_D, ROP_D, ROP_D, ROP_D, ROP_D, ROP_D,
|
|
ROP_D, ROP_D, ROP_D, ROP_D, ROP_0, /* 0x10: AF_R2_BLACK => 0 */
|
|
ROP_n_SoD, /* 0x11: AF_R2_NOTMERGESRC => NOr Image */
|
|
ROP_nSaD, /* 0x12: AF_R2_MASKNOTSRC => !Image & Dest */
|
|
ROP_nS, /* 0x13: AF_R2_NOTCOPYSRC => !Image */
|
|
ROP_SanD, /* 0x14: AF_R2_MASKSRCNOT => Image & !Dest */
|
|
ROP_nS, /* 0x15: AF_R2_NOT => !Dest */
|
|
ROP_SxD, /* 0x16: AF_R2_XORSRC => XOr Image*/
|
|
ROP_n_SaD, /* 0x17: AF_R2_NOTMASKSRC => NAnd Image */
|
|
ROP_SaD, /* 0x18: AF_R2_MASKSRC => And Image */
|
|
ROP_n_SxD, /* 0x19: AF_R2_NOTXORSRC => XNOr Image */
|
|
ROP_D, /* 0x1A: AF_R2_NOP => Dest */
|
|
ROP_nSoD, /* 0x1B: AF_R2_MERGENOTSRC => !Image | Dest */
|
|
ROP_S, /* 0x1C: AF_R2_COPYSRC => Image */
|
|
ROP_SonD, /* 0x1D: AF_R2_MERGESRCNOT => Image | !Dest */
|
|
ROP_SoD, /* 0x1E: AF_R2_MERGESRC => Or Image */
|
|
ROP_1 /* 0x1F: AF_R2_WHITE => 1 */
|
|
};
|
|
|
|
ushort PortsTable[] = {
|
|
/* VGA registers */
|
|
0x3C0, 0x3C1, 0x3C2, 0x3C3, 0x3C4, 0x3C5, 0x3C6, 0x3C7, 0x3C8, 0x3C9, 0x3CC,
|
|
0x3CE, 0x3CF, 0x3D4, 0x3D5, 0x3DA,
|
|
/* TGUI registers */
|
|
0x3D8, 0x3D9, 0x3DB, 0x43C6, 0x43C7, 0x43C8, 0x43C9, 0x83C6, 0x83C8,
|
|
#ifdef IOMAPPED
|
|
0x2120, 0x2121, 0x2122, 0x2123, 0x2124, 0x2125, 0x2126, 0x2127, 0x2128,
|
|
0x2129, 0x212A, 0x212B, 0x212C, 0x212D, 0x212E, 0x212F, 0x2130, 0x2131,
|
|
0x2132, 0x2133, 0x2134, 0x2135, 0x2136, 0x2137, 0x2138, 0x2139, 0x213A,
|
|
0x213B, 0x213C, 0x213D, 0x213E, 0x213F, 0x2140, 0x2141, 0x2142, 0x2143,
|
|
0x2144, 0x2145, 0x2146, 0x2147,
|
|
#endif
|
|
0xFFFF
|
|
};
|
|
|
|
static char tBytesPerPixel[] = { 1, 2, 2, 3 };
|
|
static char tBitsPerPixel[] = { 8, 15, 16, 24 };
|
|
|
|
/* Variables to handle the Fore/Back Mixing */
|
|
uchar UsesBackMix = 0;
|
|
uchar DontMakeBackMix = 0;
|
|
uchar BackMix = ROP_P;
|
|
uchar LineForegroundMix = ROP_P;
|
|
uchar LineForegroundMixToS = ROP_S;
|
|
uchar CurrentForegroundMix = ROP_P;
|
|
uchar HaveDoubleScan = 0;
|
|
uchar IsAceleratorOn = 0;
|
|
|
|
unsigned MMIOBASE;
|
|
unsigned long linearAddress;
|
|
unsigned long bankedAddress;
|
|
unsigned AvailableRAM;
|
|
unsigned CursorPat;
|
|
unsigned pCursorPat;
|
|
unsigned ColorPatterns[8];
|
|
unsigned pColorPatterns[8];
|
|
unsigned MonoPattern, InvMonoPattern;
|
|
unsigned pMonoPattern, pInvMonoPattern;
|
|
unsigned SelectedColorPattern;
|
|
unsigned *TextModeMemory;
|
|
int afCurrentMode = 0;
|
|
int afCurrentBank = 0;
|
|
|
|
unsigned af_y = 0;
|
|
unsigned af_color_pattern = 0;
|
|
unsigned af_bpp;
|
|
unsigned af_bytespp;
|
|
unsigned af_visible_page = 0;
|
|
unsigned af_active_page = 0;
|
|
unsigned af_height = 480;
|
|
unsigned af_width_bytes = 1024;
|
|
unsigned af_scroll_x;
|
|
unsigned af_scroll_y;
|
|
|
|
/* ToDo: perhaps optimize it */
|
|
static inline void Memcpy(uchar *d, uchar *s, int size) {
|
|
while (size--) *(d++) = *(s++);
|
|
}
|
|
|
|
/*#define BASE_PSEUDO_DMA linearAddress*/
|
|
/* Ivan's motherboard have a VERY slow access to the LFB so blits are slower
|
|
if we blit to the LFB */
|
|
#define BASE_PSEUDO_DMA bankedAddress
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
This function tests the video memory. I use 256Kb steps because I think
|
|
less than it is impossible. In fact I think all the 9440 boards have 1Mb
|
|
or 2Mb of memory. Some time ago I tried to install 1.5Mb in one board and
|
|
the BIOS reported just 1Mb. I also tried removing 0.5Mb and the BIOS
|
|
detected it OK. I think Trident's BIOS detects 256, 512, 1024 and 2048.
|
|
The first time I tested this function writing outside the memory didn't
|
|
write, but when I tested it in my machine it made a write at the 0 position.
|
|
The stranger thing is that it doesn't happend with unoptimized code.
|
|
Oh! if you wander about why such a complex test, beleive me if you don't
|
|
check all you could detect any crazy value.
|
|
|
|
***************************************************************************/
|
|
#define M256K (1 << 18)
|
|
#define M512K (1 << 19)
|
|
#define M2M (1 << 21)
|
|
|
|
#if 1
|
|
int TestMemory( ) {
|
|
/* Brut force: Try read/write to the linear space ;-) */
|
|
int size = 1 << 18;
|
|
volatile uchar *p = ((uchar *)linearAddress);
|
|
uchar temp;
|
|
uchar temp0, temp1, temp2;
|
|
int seq04, crt1e;
|
|
|
|
/* Put the chip in a mode where we can address the whole memory */
|
|
seq04 = ReadSEQ(4);
|
|
crt1e = ReadCRT(0x1E);
|
|
if ((seq04 & 8) == 0) WriteSEQ(4, seq04 | 8); /* Chain 4 */
|
|
if ((crt1e & 0x80) == 0)
|
|
WriteCRT(0x1E, crt1e | 0x80); /* Enable b16 start address */
|
|
|
|
temp0 = *p;
|
|
temp1 = p[M256K];
|
|
temp2 = p[M512K];
|
|
*p = 0xF0;
|
|
p[M256K] = 0xF0;
|
|
p[M512K] = 0xF0;
|
|
if (*p != 0xF0)
|
|
size = 0;
|
|
else {
|
|
do {
|
|
temp = p[size];
|
|
p[size] = 0xAA;
|
|
p[4] = 0;
|
|
if (p[size] != 0xAA || *p != 0xF0) break;
|
|
if (size > M256K) {
|
|
if (p[M256K] != 0xF0) break;
|
|
if (size > M512K && p[M512K] != 0xF0) break;
|
|
}
|
|
p[size] = 0x55;
|
|
p[4] = 0;
|
|
if (p[size] != 0x55 || *p != 0xF0) break;
|
|
if (size > M256K) {
|
|
if (p[M256K] != 0xF0) break;
|
|
if (size > M512K && p[M512K] != 0xF0) break;
|
|
}
|
|
p[size] = temp;
|
|
size += M256K;
|
|
} while (size < M2M);
|
|
}
|
|
*p = temp0;
|
|
p[M256K] = temp1;
|
|
p[M512K] = temp2;
|
|
if ((seq04 & 8) == 0) WriteSEQ(4, seq04);
|
|
if ((crt1e & 0x80) == 0) WriteCRT(0x1E, crt1e);
|
|
return size;
|
|
}
|
|
#else
|
|
int TestMemory( ) {
|
|
int size = 0, temp;
|
|
/* The following is completly undocumented by Trident. Seems that the video
|
|
board's BIOS tests the memory during start up and stores the result here,
|
|
isn't detected by the chip. Formally the register is called Software
|
|
Programming and is reserved */
|
|
temp = ReadCRT(0x1F);
|
|
|
|
switch (temp & 7) {
|
|
case 0:
|
|
case 4: AvailableRAM = 256 * 1024; break;
|
|
case 1:
|
|
case 5: AvailableRAM = 512 * 1024; break;
|
|
case 2:
|
|
case 6: AvailableRAM = 768 * 1024; break;
|
|
case 3: AvailableRAM = 1024 * 1024; break;
|
|
case 7: AvailableRAM = 2048 * 1024; break;
|
|
}
|
|
return size;
|
|
}
|
|
#endif
|
|
|
|
#if 0
|
|
// Was used during test. ToDo: remove it in the release
|
|
void Initialization(void)
|
|
{
|
|
int i;
|
|
|
|
/* Find the amount of installed memory */
|
|
AvailableRAM=TestMemory();
|
|
AvailableRAM=1024*1024;
|
|
/* Reserve 2Kb of memory for patterns and harware cursor */
|
|
/* Monochromatic pattern */
|
|
/* I use 128 bytes aligment because in 16bpp that required */
|
|
AvailableRAM-=128;
|
|
pMonoPattern=linearAddress+AvailableRAM;
|
|
MonoPattern=AvailableRAM>>6;
|
|
AvailableRAM-=128;
|
|
pInvMonoPattern=linearAddress+AvailableRAM;
|
|
InvMonoPattern=AvailableRAM>>6;
|
|
/* Hardware Cursor */
|
|
/* 32x32 (size) * 2 (planes) / 8 (packed) = 256 but 1K aligned */
|
|
AvailableRAM-=256+512;
|
|
pCursorPat=linearAddress+AvailableRAM;
|
|
CursorPat=AvailableRAM>>10;
|
|
/* 8 patterns of 8x8x2 bytes */
|
|
for (i=0; i<8; i++)
|
|
{
|
|
AvailableRAM-=128;
|
|
pColorPatterns[i]=linearAddress+AvailableRAM;
|
|
ColorPatterns[i]=AvailableRAM>>6;
|
|
}
|
|
SelectedColorPattern=ColorPatterns[0];
|
|
}
|
|
#endif
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Downloads a monochrome (packed bit) pattern, for use by the DrawPattScan()
|
|
and DrawPattRect() functions. This is always sized 8x8, and aligned with the
|
|
top left corner of video memory: if other alignments are desired, the pattern
|
|
will be prerotated before it is passed to this routine. @x{DrawPattScan}.
|
|
@x{DrawPattRect}.
|
|
|
|
***************************************************************************/
|
|
|
|
void Set8x8MonoPattern(AF_DRIVER *af, unsigned char *pattern) {
|
|
#ifndef WAITTILLIDLE_NOT_NEEDED
|
|
WaitGE( );
|
|
#endif
|
|
*((unsigned long *)pMonoPattern) = *((unsigned long *)pattern);
|
|
*((unsigned long *)pInvMonoPattern) = ~(*((unsigned long *)pattern));
|
|
*((unsigned long *)(pMonoPattern + 4)) = *((unsigned long *)&pattern[4]);
|
|
*((unsigned long *)(pInvMonoPattern + 4)) =
|
|
~(*((unsigned long *)&pattern[4]));
|
|
}
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Downloads a color pattern, for use by the DrawColorPattScan() and
|
|
DrawColorPattRect() functions. This is always sized 8x8, and aligned with
|
|
the top left corner of video memory: if other alignments are desired, the
|
|
pattern will be prerotated before it is passed to this routine. The color
|
|
values are presented in the native format for the current video mode, but
|
|
padded to 32 bits (so the pattern is always an 8x8 array of longs).
|
|
@x{DrawColorPattScan}. @x{DrawColorPattRect}.
|
|
|
|
// ToDo: Make 2 versions
|
|
|
|
***************************************************************************/
|
|
|
|
void Set8x8ColorPattern(AF_DRIVER *af, int index, unsigned long *pattern) {
|
|
int i;
|
|
index &= 0x7;
|
|
if (af_bpp == 8) {
|
|
#ifndef WAITTILLIDLE_NOT_NEEDED
|
|
WaitGE( );
|
|
#endif
|
|
for (i = 0; i < 64; i++)
|
|
*(((uchar *)pColorPatterns[index]) + i) = pattern[i];
|
|
} else {
|
|
#ifndef WAITTILLIDLE_NOT_NEEDED
|
|
WaitGE( );
|
|
#endif
|
|
for (i = 0; i < 64; i++)
|
|
*(((ushort *)pColorPatterns[index]) + i) = pattern[i];
|
|
}
|
|
}
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Selects one of the patterns previously downloaded by Set8x8ColorPattern().
|
|
@x{Set8x8ColorPattern}.
|
|
|
|
***************************************************************************/
|
|
|
|
void Use8x8ColorPattern(AF_DRIVER *af, int index) {
|
|
SelectedColorPattern = ColorPatterns[index & 0x7];
|
|
}
|
|
|
|
/*****************************************************************************
|
|
|
|
The TGUI9440 chip supports only Besenham lines, I think they are VERY easy
|
|
to implement in chips and that's the reason because old chips use it.
|
|
These lines works with parameters for one octant, the one defined by:
|
|
|
|
delta X > delta Y > 0
|
|
|
|
To create any line the chip provides 3 bits that selects the octant.
|
|
|
|
*****************************************************************************/
|
|
|
|
void DrawLine(AF_DRIVER *af, unsigned long color, fixed x1, fixed y1, fixed x2,
|
|
fixed y2) {
|
|
int dX, dY, dir = SolidDrawing | PatFromDisplay | SourceDataDisplay;
|
|
|
|
/* round coordinates from fixed point to integer */
|
|
x1 = (x1 + 0x8000) >> 16;
|
|
y1 = ((y1 + 0x8000) >> 16) + af_y;
|
|
x2 = (x2 + 0x8000) >> 16;
|
|
y2 = ((y2 + 0x8000) >> 16) + af_y;
|
|
|
|
/* Check if dY is positive */
|
|
if (y1 > y2) { /* No then reverse Y direction */
|
|
dir |= YDecreasing;
|
|
dY = y1 - y2;
|
|
} else
|
|
dY = y2 - y1;
|
|
|
|
/* Check if dX is positive */
|
|
if (x1 > x2) { /* No then reverse Y direction */
|
|
dir |= XDecreasing;
|
|
dX = x1 - x2;
|
|
} else
|
|
dX = x2 - x1;
|
|
|
|
/* Check for dX>dY */
|
|
if (dY > dX) { /* No then swap */
|
|
int temp = dX;
|
|
dX = dY;
|
|
dY = temp;
|
|
dir |= YMajor;
|
|
}
|
|
|
|
WaitGEfifo( );
|
|
if (CurrentForegroundMix != LineForegroundMix) {
|
|
SetForegroundMix(LineForegroundMix);
|
|
CurrentForegroundMix = LineForegroundMix;
|
|
}
|
|
SetForeground(color);
|
|
|
|
/* Now dX > dY > 0 and all the flags for the octant are calculated */
|
|
SetXYLocation(x1, y1);
|
|
SetLineSteps(dY, dX);
|
|
SetErrAndLen(dY, dX);
|
|
SetDrawFlags(dir);
|
|
DoBresenhamLine( );
|
|
}
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Sets the mask used for stipple lines. @x{DrawStippleLine}.@p
|
|
I'm not sure about it so here is my guess: TGUI9440 have a 16 bits
|
|
register (GER44,GER45) to set the mask used for patterned lines so I guess
|
|
that's this function is to setup this value.@p
|
|
|
|
***************************************************************************/
|
|
|
|
void SetLineStipple(AF_DRIVER *af, unsigned short stipple) {
|
|
WaitGEfifo( );
|
|
SetPenStyleMask(stipple);
|
|
}
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Sets the repeat counter for the mask used in stipple lines.
|
|
@x{DrawStippleLine}.@p
|
|
I'm not sure about it so here is my guess: TGUI9440 have an 8 bits
|
|
register (GER47) to set the scale of the pattern for patterned lines. A value
|
|
of 0 means that each bit in the pattern is 1 dot, a value of 1 expands
|
|
each pixel to 2 dots and so on.@p
|
|
|
|
***************************************************************************/
|
|
|
|
void SetLineStippleCount(AF_DRIVER *af, unsigned long count) {
|
|
WaitGEfifo( );
|
|
SetStyleMaskRepeatCount(count);
|
|
}
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Draws a stipple line (patterned, dotted). SetLineStipple sets the pattern
|
|
used and SetLineStippleCount the scale. @x{SetLineStipple}.
|
|
@x{SetLineStippleCount}.@p
|
|
Note: This function doesn't call drawline, it is almost the same code
|
|
repeated. That's to increase speed because in this way I can make the
|
|
Bresenham parameters calculation in parallel with the GE.
|
|
|
|
***************************************************************************/
|
|
|
|
void DrawStippleLine(AF_DRIVER *af, unsigned long foreColor,
|
|
unsigned long backColor, fixed x1, fixed y1, fixed x2,
|
|
fixed y2) {
|
|
int dX, dY, dir = PatternedLines | PatFromDisplay | SourceDataDisplay;
|
|
|
|
/* round coordinates from fixed point to integer */
|
|
x1 = (x1 + 0x8000) >> 16;
|
|
y1 = ((y1 + 0x8000) >> 16) + af_y;
|
|
x2 = (x2 + 0x8000) >> 16;
|
|
y2 = ((y2 + 0x8000) >> 16) + af_y;
|
|
|
|
/* Check if dY is positive */
|
|
if (y1 > y2) { /* No then reverse Y direction */
|
|
dir |= YDecreasing;
|
|
dY = y1 - y2;
|
|
} else
|
|
dY = y2 - y1;
|
|
|
|
/* Check if dX is positive */
|
|
if (x1 > x2) { /* No then reverse Y direction */
|
|
dir |= XDecreasing;
|
|
dX = x1 - x2;
|
|
} else
|
|
dX = x2 - x1;
|
|
|
|
/* Check for dX>dY */
|
|
if (dY > dX) { /* No then swap */
|
|
int temp = dX;
|
|
dX = dY;
|
|
dY = temp;
|
|
dir |= YMajor;
|
|
}
|
|
|
|
WaitGEfifo( );
|
|
if (CurrentForegroundMix != LineForegroundMix) {
|
|
SetForegroundMix(LineForegroundMix);
|
|
CurrentForegroundMix = LineForegroundMix;
|
|
}
|
|
SetForeground(foreColor);
|
|
SetBackground(backColor);
|
|
|
|
/* Now dX > dY > 0 and all the flags for the octant are calculated */
|
|
SetXYLocation(x1, y1);
|
|
SetLineSteps(dY, dX);
|
|
SetErrAndLen(dY, dX);
|
|
SetDrawFlags(dir);
|
|
DoBresenhamLine( );
|
|
}
|
|
|
|
void SetMix(AF_DRIVER *af, long foreMix, long backMix) {
|
|
uchar af_fore_mix = 0;
|
|
uchar af_back_mix = 0;
|
|
|
|
/* Limit the values to my range */
|
|
af_fore_mix = foreMix & 0x1F;
|
|
|
|
if (backMix == 0)
|
|
af_back_mix = af_fore_mix;
|
|
else
|
|
af_back_mix = backMix & 0x1F;
|
|
|
|
/* Foreground mix used by lines and pattern fills */
|
|
LineForegroundMix = ROPEquiv[af_fore_mix];
|
|
LineForegroundMixToS = ROPImageEquiv[af_fore_mix];
|
|
/* 9440 doesn't have Background mixing but I make it in 2 steps */
|
|
UsesBackMix = (af_back_mix != af_fore_mix);
|
|
BackMix = ROPEquiv[af_back_mix];
|
|
DontMakeBackMix = (BackMix == ROP_D);
|
|
}
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Fills a rectangle in the current foreground mix mode.
|
|
|
|
***************************************************************************/
|
|
|
|
void DrawRect(AF_DRIVER *af, unsigned long color, long left, long top,
|
|
long width, long height) {
|
|
WaitGEfifo( );
|
|
if (CurrentForegroundMix != LineForegroundMix) {
|
|
SetForegroundMix(LineForegroundMix);
|
|
CurrentForegroundMix = LineForegroundMix;
|
|
}
|
|
SetForeground(color);
|
|
SetDrawFlags(SolidDrawing | PatMono);
|
|
SetXYLocation(left, top + af_y);
|
|
SetDimensions(width - 1, height - 1);
|
|
DoBlit( );
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" void DrawRawRect(unsigned long color, long left, long top,
|
|
long width, long height);
|
|
#endif
|
|
// Internally used to clean the screen
|
|
void DrawRawRect(unsigned long color, long left, long top, long width,
|
|
long height) {
|
|
WaitGEfifo( );
|
|
if (CurrentForegroundMix != LineForegroundMix) {
|
|
SetForegroundMix(LineForegroundMix);
|
|
CurrentForegroundMix = LineForegroundMix;
|
|
}
|
|
SetForeground(color);
|
|
SetDrawFlags(SolidDrawing | PatMono);
|
|
SetXYLocation(left, top + af_y);
|
|
SetDimensions(width, height);
|
|
DoBlitDontWait( );
|
|
}
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Fills a scanline in the current foreground mix mode. Draws up to but
|
|
not including the second x coordinate. If the second coord is less than the
|
|
first, they are swapped. If they are equal, nothing is drawn.
|
|
|
|
***************************************************************************/
|
|
|
|
void DrawScan(AF_DRIVER *af, long color, long y, long x1, long x2) {
|
|
unsigned mode = SolidDrawing | PatMono;
|
|
int w;
|
|
|
|
if (x1 < x2)
|
|
w = x2 - x1;
|
|
else {
|
|
if (x2 < x1) {
|
|
w = x1 - x2;
|
|
mode |= XDecreasing;
|
|
x1--;
|
|
/* In this case x1 is the second coordinate and the VBE/AF 1.0 says
|
|
that we must draw [1st,2nd) */
|
|
} else
|
|
return;
|
|
}
|
|
|
|
WaitGEfifo( );
|
|
if (CurrentForegroundMix != LineForegroundMix) {
|
|
SetForegroundMix(LineForegroundMix);
|
|
CurrentForegroundMix = LineForegroundMix;
|
|
}
|
|
SetForeground(color);
|
|
SetDrawFlags(mode);
|
|
SetXYLocation(x1, y + af_y);
|
|
SetWidth_1(w);
|
|
DoScan( );
|
|
}
|
|
|
|
void DrawScanList(AF_DRIVER *af, unsigned long color, long y, long length,
|
|
short *scans) {
|
|
unsigned mode;
|
|
int w, i;
|
|
int x1, x2;
|
|
|
|
WaitGEfifo( );
|
|
if (CurrentForegroundMix != LineForegroundMix) {
|
|
SetForegroundMix(LineForegroundMix);
|
|
CurrentForegroundMix = LineForegroundMix;
|
|
}
|
|
SetForeground(color);
|
|
SetYLocation(y + af_y);
|
|
|
|
for (i = 0; i < length; i++) {
|
|
x1 = scans[i * 2];
|
|
x2 = scans[i * 2 + 1];
|
|
|
|
if (x1 < x2) {
|
|
w = x2 - x1;
|
|
mode = SolidDrawing | PatMono;
|
|
} else {
|
|
if (x2 < x1) {
|
|
w = x1 - x2;
|
|
mode = SolidDrawing | PatMono | XDecreasing;
|
|
x1--;
|
|
} else
|
|
continue;
|
|
}
|
|
|
|
WaitGEfifo( );
|
|
SetDrawFlags(mode);
|
|
SetXLocation(x1);
|
|
SetWidth_1(w);
|
|
DoScan( );
|
|
}
|
|
}
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Fills a rectangle using the current mono pattern. Set pattern bits are
|
|
drawn using the specified foreground color and the foreground mix mode, and
|
|
clear bits use the background color and background mix mode.
|
|
|
|
***************************************************************************/
|
|
|
|
void DrawPattRect(AF_DRIVER *af, unsigned long foreColor,
|
|
unsigned long backColor, long left, long top, long width,
|
|
long height) {
|
|
if (UsesBackMix) {
|
|
/* First pass we use the FMIX and the normal pattern */
|
|
WaitGEfifo( );
|
|
SetPatternLocation(MonoPattern);
|
|
SetForegroundMix(LineForegroundMix);
|
|
|
|
SetForeground(foreColor);
|
|
SetBackground(0);
|
|
SetDrawFlags(PatternedDrawing | PatMono | PatFromDisplay |
|
|
SourceDataDisplay | TransparentEnable);
|
|
SetXYLocation(left, top + af_y);
|
|
SetDimensions(width - 1, height - 1);
|
|
DoBlitDontWait( );
|
|
|
|
/* If the back mix is No Operation just skip it */
|
|
if (DontMakeBackMix) {
|
|
CurrentForegroundMix = LineForegroundMix;
|
|
return;
|
|
}
|
|
|
|
/* Second pass we use the reverse pattern and the background as a
|
|
foreground */
|
|
WaitGEfifo( );
|
|
SetPatternLocation(InvMonoPattern);
|
|
SetForegroundMix(BackMix);
|
|
CurrentForegroundMix = BackMix;
|
|
|
|
SetForeground(backColor);
|
|
DoBlit( );
|
|
return;
|
|
}
|
|
/* That's supported */
|
|
WaitGEfifo( );
|
|
SetForeground(foreColor);
|
|
SetBackground(backColor);
|
|
if (CurrentForegroundMix != LineForegroundMix) {
|
|
SetForegroundMix(LineForegroundMix);
|
|
CurrentForegroundMix = LineForegroundMix;
|
|
}
|
|
SetPatternLocation(MonoPattern);
|
|
SetDrawFlags(PatternedDrawing | PatMono | PatFromDisplay |
|
|
SourceDataDisplay);
|
|
SetXYLocation(left, top + af_y);
|
|
SetDimensions(width - 1, height - 1);
|
|
DoBlit( );
|
|
}
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Fills a scanline using the current mono pattern. Set pattern bits are
|
|
drawn using the specified foreground color and the foreground mix mode, and
|
|
clear bits use the background color and background mix mode.
|
|
|
|
***************************************************************************/
|
|
|
|
void DrawPattScan(AF_DRIVER *af, long foreColor, long backColor, long y,
|
|
long x1, long x2) {
|
|
unsigned mode =
|
|
PatternedDrawing | PatMono | PatFromDisplay | SourceDataDisplay;
|
|
int w;
|
|
|
|
if (UsesBackMix) {
|
|
if (x1 < x2)
|
|
/*af->?*/ DrawPattRect(af, foreColor, backColor, x1, y, x2 - x1, 1);
|
|
else if (x2 < x1)
|
|
DrawPattRect(af, foreColor, backColor, x2, y, x1 - x2, 1);
|
|
return;
|
|
}
|
|
|
|
if (x1 < x2)
|
|
w = x2 - x1;
|
|
else {
|
|
if (x2 < x1) {
|
|
w = x1 - x2;
|
|
mode |= XDecreasing;
|
|
x1--;
|
|
} else
|
|
return;
|
|
}
|
|
|
|
WaitGEfifo( );
|
|
SetForeground(foreColor);
|
|
SetBackground(backColor);
|
|
if (CurrentForegroundMix != LineForegroundMix) {
|
|
SetForegroundMix(LineForegroundMix);
|
|
CurrentForegroundMix = LineForegroundMix;
|
|
}
|
|
SetPatternLocation(MonoPattern);
|
|
SetDrawFlags(mode);
|
|
SetXYLocation(x1, y + af_y);
|
|
SetWidth_1(w);
|
|
DoScan( );
|
|
}
|
|
|
|
void DrawPattScanList(AF_DRIVER *af, unsigned long foreColor,
|
|
unsigned long backColor, long y, long length,
|
|
short *scans) {
|
|
unsigned mode;
|
|
int w;
|
|
int x1, x2, i;
|
|
|
|
if (UsesBackMix) {
|
|
for (i = 0; i < length; i++) {
|
|
x1 = scans[i * 2];
|
|
x2 = scans[i * 2 + 1];
|
|
if (x1 < x2)
|
|
DrawPattRect(af, foreColor, backColor, x1, y, x2 - x1, 1);
|
|
else if (x2 < x1)
|
|
DrawPattRect(af, foreColor, backColor, x2, y, x1 - x2, 1);
|
|
}
|
|
return;
|
|
}
|
|
|
|
WaitGEfifo( );
|
|
SetForeground(foreColor);
|
|
SetBackground(backColor);
|
|
if (CurrentForegroundMix != LineForegroundMix) {
|
|
SetForegroundMix(LineForegroundMix);
|
|
CurrentForegroundMix = LineForegroundMix;
|
|
}
|
|
SetPatternLocation(MonoPattern);
|
|
SetYLocation(y + af_y);
|
|
|
|
for (i = 0; i < length; i++) {
|
|
x1 = scans[i * 2];
|
|
x2 = scans[i * 2 + 1];
|
|
|
|
if (x1 < x2) {
|
|
w = x2 - x1;
|
|
mode =
|
|
PatternedDrawing | PatMono | PatFromDisplay | SourceDataDisplay;
|
|
} else {
|
|
if (x2 < x1) {
|
|
w = x1 - x2;
|
|
mode = PatternedDrawing | PatMono | PatFromDisplay |
|
|
SourceDataDisplay | XDecreasing;
|
|
x1--;
|
|
} else
|
|
continue;
|
|
}
|
|
|
|
WaitGEfifo( );
|
|
SetDrawFlags(mode);
|
|
SetXLocation(x1);
|
|
SetWidth_1(w);
|
|
DoScan( );
|
|
}
|
|
}
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Fills a rectangle using the current color pattern and mix mode.
|
|
|
|
***************************************************************************/
|
|
|
|
void DrawColorPattRect(AF_DRIVER *af, long left, long top, long width,
|
|
long height) {
|
|
WaitGEfifo( );
|
|
if (CurrentForegroundMix != LineForegroundMix) {
|
|
SetForegroundMix(LineForegroundMix);
|
|
CurrentForegroundMix = LineForegroundMix;
|
|
}
|
|
SetPatternLocation(SelectedColorPattern);
|
|
SetDrawFlags(PatternedDrawing | PatFromDisplay | SourceDataDisplay);
|
|
SetXYLocation(left, top + af_y);
|
|
SetDimensions(width - 1, height - 1);
|
|
DoBlit( );
|
|
}
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Fills a scanline using the current mono pattern. Set pattern bits are
|
|
drawn using the specified foreground color and the foreground mix mode, and
|
|
clear bits use the background color and background mix mode.
|
|
|
|
***************************************************************************/
|
|
|
|
void DrawColorPattScan(AF_DRIVER *af, long y, long x1, long x2) {
|
|
unsigned mode = PatternedDrawing | PatFromDisplay | SourceDataDisplay;
|
|
int w;
|
|
|
|
if (x1 < x2)
|
|
w = x2 - x1;
|
|
else {
|
|
if (x2 < x1) {
|
|
w = x1 - x2;
|
|
mode |= XDecreasing;
|
|
x1--;
|
|
} else
|
|
return;
|
|
}
|
|
|
|
WaitGEfifo( );
|
|
if (CurrentForegroundMix != LineForegroundMix) {
|
|
SetForegroundMix(LineForegroundMix);
|
|
CurrentForegroundMix = LineForegroundMix;
|
|
}
|
|
SetPatternLocation(SelectedColorPattern);
|
|
SetDrawFlags(mode);
|
|
SetXYLocation(x1, y + af_y);
|
|
SetWidth_1(w);
|
|
DoScan( );
|
|
}
|
|
|
|
void DrawColorPattScanList(AF_DRIVER *af, long y, long length, short *scans) {
|
|
unsigned mode;
|
|
int w, x1, x2, i;
|
|
|
|
WaitGEfifo( );
|
|
if (CurrentForegroundMix != LineForegroundMix) {
|
|
SetForegroundMix(LineForegroundMix);
|
|
CurrentForegroundMix = LineForegroundMix;
|
|
}
|
|
SetPatternLocation(SelectedColorPattern);
|
|
SetYLocation(y + af_y);
|
|
|
|
for (i = 0; i < length; i++) {
|
|
x1 = scans[i * 2];
|
|
x2 = scans[i * 2 + 1];
|
|
|
|
if (x1 < x2) {
|
|
w = x2 - x1;
|
|
mode = PatternedDrawing | PatFromDisplay | SourceDataDisplay;
|
|
} else {
|
|
if (x2 < x1) {
|
|
w = x1 - x2;
|
|
mode = PatternedDrawing | PatFromDisplay | SourceDataDisplay |
|
|
XDecreasing;
|
|
x1--;
|
|
} else
|
|
continue;
|
|
}
|
|
|
|
WaitGEfifo( );
|
|
SetDrawFlags(mode);
|
|
SetXLocation(x1);
|
|
SetWidth_1(w);
|
|
DoScan( );
|
|
}
|
|
}
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Blits from one part of video memory to another, using the specified
|
|
mix operation. This must correctly handle the case where the two regions
|
|
overlap.
|
|
|
|
***************************************************************************/
|
|
|
|
void BitBlt(AF_DRIVER *af, long left, long top, long width, long height,
|
|
long dstLeft, long dstTop, long op) {
|
|
uchar BlitForegroundMix = ROPImageEquiv[op & 0x1F];
|
|
unsigned direction = PatternedDrawing | SourceDataDisplay;
|
|
|
|
/* Check for horizontal overlap */
|
|
if (dstLeft > left && dstLeft < left + width) {
|
|
direction |= XDecreasing;
|
|
dstLeft += width - 1;
|
|
left += width;
|
|
}
|
|
/* Check for vertical overlap */
|
|
if (dstTop > top && dstTop < top + height) {
|
|
direction |= YDecreasing;
|
|
dstTop += height - 1;
|
|
top += height;
|
|
}
|
|
WaitGEfifo( );
|
|
if (CurrentForegroundMix != BlitForegroundMix) {
|
|
SetForegroundMix(BlitForegroundMix);
|
|
CurrentForegroundMix = BlitForegroundMix;
|
|
}
|
|
SetDrawFlags(direction);
|
|
SetXYLocation(dstLeft, dstTop + af_y);
|
|
SetXYSource(left, top + af_y);
|
|
SetDimensions(width, height);
|
|
DoBlit( );
|
|
}
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Blits from one part of video memory to another, using the specified
|
|
mix operation and skipping any source pixels which match the specified
|
|
transparent color. Results are undefined if the two regions overlap.
|
|
|
|
***************************************************************************/
|
|
|
|
void SrcTransBlt(AF_DRIVER *af, long left, long top, long width, long height,
|
|
long dstLeft, long dstTop, long op,
|
|
unsigned long transparent) {
|
|
uchar BlitForegroundMix = ROPImageEquiv[op & 0x1F];
|
|
WaitGEfifo( );
|
|
if (CurrentForegroundMix != BlitForegroundMix) {
|
|
SetForegroundMix(BlitForegroundMix);
|
|
CurrentForegroundMix = BlitForegroundMix;
|
|
}
|
|
SetDrawFlags(PatternedDrawing | SourceDataDisplay | TransparentEnable);
|
|
SetBackground(transparent);
|
|
SetXYLocation(dstLeft, dstTop + af_y);
|
|
SetXYSource(left, top + af_y);
|
|
SetDimensions(width, height);
|
|
DoBlit( );
|
|
}
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Copies from system memory to the screen.
|
|
|
|
***************************************************************************/
|
|
|
|
void BitBltSys(AF_DRIVER *af, void *srcAddr, long srcPitch, long srcLeft,
|
|
long srcTop, long width, long height, long dstLeft, long dstTop,
|
|
long op) {
|
|
uchar BlitForegroundMix = ROPImageEquiv[op & 0x1F];
|
|
int n, i;
|
|
unsigned addr;
|
|
|
|
/* adjust source bitmap pointers */
|
|
switch (af_bpp) {
|
|
case 8:
|
|
addr = (unsigned)srcAddr + srcLeft + srcTop * srcPitch;
|
|
n = (width + 3) / 4;
|
|
break;
|
|
|
|
case 15:
|
|
case 16:
|
|
addr = (unsigned)srcAddr + srcLeft * 2 + srcTop * srcPitch;
|
|
n = (width + 1) / 2;
|
|
break;
|
|
|
|
default: return;
|
|
}
|
|
|
|
WaitGE( );
|
|
if (CurrentForegroundMix != BlitForegroundMix) {
|
|
SetForegroundMix(BlitForegroundMix);
|
|
CurrentForegroundMix = BlitForegroundMix;
|
|
}
|
|
SetDrawFlags(PatternedDrawing | PatFromDisplay);
|
|
SetXYLocation(dstLeft, dstTop + af_y);
|
|
/* Source X bits 0-1 are the offset in the double word */
|
|
SetXYSource(0, 0);
|
|
SetDimensions(width - 1, height - 1);
|
|
|
|
DoBlit( );
|
|
/* copy data to the start of memory */
|
|
for (i = 0; i < height; i++) {
|
|
asm(" rep ; movsl "
|
|
:
|
|
: "c"(n), "S"(addr), "D"(BASE_PSEUDO_DMA)
|
|
: "%ecx", "%esi", "%edi");
|
|
addr += srcPitch;
|
|
}
|
|
}
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Copies from system memory to the screen, skipping any source pixels that
|
|
match the specified transparent color.
|
|
|
|
***************************************************************************/
|
|
|
|
void SrcTransBltSys(AF_DRIVER *af, void *srcAddr, long srcPitch, long srcLeft,
|
|
long srcTop, long width, long height, long dstLeft,
|
|
long dstTop, long op, unsigned long transparent) {
|
|
uchar BlitForegroundMix = ROPImageEquiv[op & 0x1F];
|
|
int n, i;
|
|
unsigned addr;
|
|
|
|
/* adjust source bitmap pointers */
|
|
switch (af_bpp) {
|
|
case 8:
|
|
addr = (unsigned)srcAddr + srcLeft + srcTop * srcPitch;
|
|
n = (width + 3) / 4;
|
|
break;
|
|
|
|
case 15:
|
|
case 16:
|
|
addr = (unsigned)srcAddr + srcLeft * 2 + srcTop * srcPitch;
|
|
n = (width + 1) / 2;
|
|
break;
|
|
|
|
default: return;
|
|
}
|
|
|
|
WaitGE( );
|
|
if (CurrentForegroundMix != BlitForegroundMix) {
|
|
SetForegroundMix(BlitForegroundMix);
|
|
CurrentForegroundMix = BlitForegroundMix;
|
|
}
|
|
SetDrawFlags(PatternedDrawing | PatFromDisplay | TransparentEnable);
|
|
SetBackground(transparent);
|
|
SetXYLocation(dstLeft, dstTop + af_y);
|
|
/* Source X bits 0-1 are the offset in the double word */
|
|
SetXYSource(0, 0);
|
|
SetDimensions(width - 1, height - 1);
|
|
|
|
DoBlit( );
|
|
/* copy data to the start of memory */
|
|
for (i = 0; i < height; i++) {
|
|
asm(" rep ; movsl "
|
|
:
|
|
: "c"(n), "S"(addr), "D"(BASE_PSEUDO_DMA)
|
|
: "%ecx", "%esi", "%edi");
|
|
addr += srcPitch;
|
|
}
|
|
}
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Expands a monochrome bitmap from system memory onto the screen.
|
|
|
|
***************************************************************************/
|
|
|
|
void PutMonoImage(AF_DRIVER *af, long foreColor, long backColor, long dstX,
|
|
long dstY, long byteWidth, long srcX, long srcY, long width,
|
|
long height, unsigned char *image) {
|
|
int n, off, i, mode;
|
|
|
|
/* Move to the byte position in the mono-image */
|
|
image += srcY * byteWidth + srcX / 8;
|
|
/* Calculate how many dwords is a line */
|
|
n = (width + 31) / 32;
|
|
/* Calculate the offset inside the byte */
|
|
off = (srcX & 7) << 24;
|
|
|
|
WaitGE( );
|
|
if (CurrentForegroundMix != LineForegroundMixToS) {
|
|
SetForegroundMix(LineForegroundMixToS);
|
|
CurrentForegroundMix = LineForegroundMixToS;
|
|
}
|
|
SetForeground(foreColor);
|
|
mode = PatternedDrawing | SourceDataMono | PatMono | PatFromDisplay |
|
|
SourceDataSystem | off;
|
|
if (UsesBackMix & DontMakeBackMix) {
|
|
mode |= TransparentEnable;
|
|
/* For some strange reason (silicon bug?) if we use transparent draw
|
|
with fore=back=0 the result is nothing drawed!!! I spend some time
|
|
before figuring out why the labels in Allegro buttons were invisible
|
|
*/
|
|
SetBackground(1);
|
|
} else {
|
|
SetBackground(backColor);
|
|
}
|
|
SetDrawFlags(mode);
|
|
SetXYLocation(dstX, dstY + af_y);
|
|
// SetXYSource(0xFF,0);
|
|
SetDimensions(width - 1, height - 1);
|
|
DoBlit( );
|
|
/* copy data to the start of memory */
|
|
for (i = 0; i < height; i++) {
|
|
asm(" rep ; movsl "
|
|
:
|
|
: "c"(n), "S"(image), "D"(BASE_PSEUDO_DMA)
|
|
: "%ecx", "%esi", "%edi");
|
|
image += byteWidth;
|
|
}
|
|
}
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Draws a filled trapezoid, using the current foreground mix mode.@p
|
|
TGUI9440 doesn't have trapezoids, I think it was introduced in 96xx chips.
|
|
I implemented it using scan lines, I think that's faster than a software
|
|
trapezoid.
|
|
|
|
***************************************************************************/
|
|
|
|
void DrawTrap(AF_DRIVER *af, unsigned long color, AF_TRAP *trap) {
|
|
int ix1, ix2;
|
|
int y;
|
|
|
|
WaitGEfifo( );
|
|
if (CurrentForegroundMix != LineForegroundMix) {
|
|
SetForegroundMix(LineForegroundMix);
|
|
CurrentForegroundMix = LineForegroundMix;
|
|
}
|
|
SetForeground(color);
|
|
SetDrawFlags(SolidDrawing | PatMono);
|
|
|
|
y = trap->y + af_y;
|
|
/* scan-convert the trapezoid */
|
|
while (trap->count--) {
|
|
/* Convert X values to ints rounding */
|
|
ix1 = (trap->x1 + 0x8000) >> 16;
|
|
ix2 = (trap->x2 + 0x8000) >> 16;
|
|
|
|
if (ix2 < ix1) {
|
|
int tmp = ix1;
|
|
ix1 = ix2;
|
|
ix2 = tmp;
|
|
}
|
|
|
|
WaitGEfifo( );
|
|
SetXYLocation(ix1, y);
|
|
SetWidth(ix2 - ix1);
|
|
DoScan( );
|
|
|
|
trap->x1 += trap->slope1;
|
|
trap->x2 += trap->slope2;
|
|
y++;
|
|
}
|
|
trap->y = y - af_y;
|
|
}
|
|
|
|
unsigned cur_hot_x, cur_hot_y;
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Sets the hardware cursor shape.
|
|
|
|
// ToDo split it in various
|
|
|
|
***************************************************************************/
|
|
|
|
void SetCursor(AF_DRIVER *af, AF_CURSOR *cursor) {
|
|
int i;
|
|
unsigned long *p = (unsigned long *)pCursorPat;
|
|
|
|
#ifndef WAITTILLIDLE_NOT_NEEDED
|
|
if (IsAceleratorOn) WaitGE( );
|
|
#endif
|
|
if (HaveDoubleScan) {
|
|
if (af_bpp == 8) {
|
|
for (i = 0; i < 32; i++) {
|
|
p[i * 8 + 4] = p[i * 8 + 0] = ~cursor->andMask[i];
|
|
p[i * 8 + 5] = p[i * 8 + 1] = cursor->xorMask[i];
|
|
p[i * 8 + 2] = p[i * 8 + 6] = 0xFFFFFFFF;
|
|
p[i * 8 + 3] = p[i * 8 + 7] = 0;
|
|
}
|
|
} else {
|
|
for (i = 0; i < 32; i++) {
|
|
p[i * 8 + 4] = p[i * 8 + 0] = ~cursor->andMask[i];
|
|
p[i * 8 + 5] = p[i * 8 + 1] =
|
|
cursor->xorMask[i] ^ cursor->andMask[i];
|
|
p[i * 8 + 2] = p[i * 8 + 6] = 0xFFFFFFFF;
|
|
p[i * 8 + 3] = p[i * 8 + 7] = 0;
|
|
}
|
|
}
|
|
} else {
|
|
if (af_bpp == 8) {
|
|
for (i = 0; i < 32; i++) {
|
|
p[i * 2] = ~cursor->andMask[i];
|
|
p[i * 2 + 1] = cursor->xorMask[i];
|
|
}
|
|
} else {
|
|
for (i = 0; i < 32; i++) {
|
|
p[i * 2] = ~cursor->andMask[i];
|
|
p[i * 2 + 1] = cursor->xorMask[i] ^ cursor->andMask[i];
|
|
}
|
|
}
|
|
}
|
|
cur_hot_x = cursor->hotx;
|
|
cur_hot_y = cursor->hoty;
|
|
}
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Sets the hardware cursor position.
|
|
|
|
***************************************************************************/
|
|
|
|
void SetCursorPos(AF_DRIVER *af, long x, long y) {
|
|
x -= cur_hot_x;
|
|
y -= cur_hot_y;
|
|
|
|
if (HaveDoubleScan) y *= 2;
|
|
/* Allow small negative coordinates moving inside the cursor, Allegro needs
|
|
it */
|
|
if (y < 0) {
|
|
WriteCRT(0x47, -y);
|
|
y = 0;
|
|
} else
|
|
WriteCRT(0x47, 0);
|
|
if (x < 0) {
|
|
WriteCRT(0x46, -x);
|
|
x = 0;
|
|
} else
|
|
WriteCRT(0x46, 0);
|
|
WriteCRT(0x40, x);
|
|
WriteCRT(0x41, x >> 8);
|
|
WriteCRT(0x42, y);
|
|
WriteCRT(0x43, y >> 8);
|
|
}
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Sets the hardware cursor color.@p
|
|
Not supported by TGUI9440, I think 968x adds some registers for it.
|
|
|
|
***************************************************************************/
|
|
|
|
void SetCursorColor(AF_DRIVER *af, unsigned char red, unsigned char green,
|
|
unsigned char blue) {
|
|
/* I disabled it because it normally mess the things.
|
|
if (af_bpp==8)
|
|
{
|
|
outportb(WriteDataAddress,0);
|
|
outportb(PaletteDataRegister,red/4);
|
|
outportb(PaletteDataRegister,green/4);
|
|
outportb(PaletteDataRegister,blue/4);
|
|
}
|
|
*/
|
|
}
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Turns the hardware cursor on or off.
|
|
|
|
***************************************************************************/
|
|
|
|
void ShowCursor(AF_DRIVER *af, long visible) {
|
|
unsigned mode = visible ? 0x80 : 0;
|
|
mode |= HaveDoubleScan ? 1 : 0;
|
|
WriteCRT(0x50, mode);
|
|
}
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
C-callable bank switch function.
|
|
|
|
***************************************************************************/
|
|
|
|
void SetBank(AF_DRIVER *af, long bank) {
|
|
#ifdef INCLUDE_OLD_INERTIA_STUFF
|
|
afCurBank = bank;
|
|
#endif
|
|
/* TGUI supports individual banks for read & write so we must set both */
|
|
outportw(DestinationSegmentAddress, bank | (bank << 8));
|
|
}
|
|
|
|
/* SetBank32:
|
|
* Relocatable bank switch function. This is called with a bank number in
|
|
* %edx.
|
|
*/
|
|
|
|
asm ("
|
|
.globl _SetBank32, _SetBank32End
|
|
|
|
.align 4
|
|
_SetBank32:
|
|
pushl %eax
|
|
pushl %edx
|
|
movb %dl, %al
|
|
movb %dl, %ah
|
|
movw $0x03D8, %dx
|
|
outw %ax, %dx
|
|
popl %edx
|
|
popl %eax
|
|
ret
|
|
|
|
_SetBank32End:
|
|
");
|
|
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Palette setting routine. Palette values are in 8 bits format because some
|
|
boards support 8 bits DAC and not only 6 bits.
|
|
|
|
***************************************************************************/
|
|
|
|
void SetPaletteData(AF_DRIVER *af, AF_PALETTE *pal, long num, long index, long waitVRT)
|
|
{
|
|
int i;
|
|
|
|
if (waitVRT) WaitVRT( );
|
|
|
|
outportb(WriteDataAddress, index);
|
|
for (i = 0; i < num; i++) {
|
|
outportb(PaletteDataRegister, pal[i].red / 4);
|
|
outportb(PaletteDataRegister, pal[i].green / 4);
|
|
outportb(PaletteDataRegister, pal[i].blue / 4);
|
|
}
|
|
}
|
|
|
|
/* GetDisplayStartStatus:
|
|
*/
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Status poll for triple buffering. Not possible on the majority of
|
|
present cards: this function is just a placeholder.@p
|
|
This must report if the Vertical Retrace Interval taked effect and the
|
|
Display Start were transfered.@p
|
|
Lamentably TGUI9440 doesn't set 3C2.b7, that's a clear violation to the
|
|
VGA standard, Trident people must do it, like CHIPS does.
|
|
|
|
***************************************************************************/
|
|
|
|
int GetDisplayStartStatus(AF_DRIVER *af)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Hardware scrolling function. The waitVRT value may be one of:@p
|
|
|
|
-1 = don't set hardware, just store values for next page flip to use@*
|
|
0 = set values and return immediately@*
|
|
1 = set values and wait for retrace@*
|
|
|
|
***************************************************************************/
|
|
|
|
void SetDisplayStart(AF_DRIVER *af, long x, long y, long waitVRT)
|
|
{
|
|
long addr;
|
|
uchar temp;
|
|
int PEL;
|
|
|
|
if (waitVRT >= 0) {
|
|
addr = (((y + af_visible_page * af_height) * af_width_bytes) +
|
|
(x * af_bytespp));
|
|
PEL = addr & 3;
|
|
addr /= 4;
|
|
|
|
/* Wait until we have a retrace (H or V) */
|
|
while (inportb(0x3DA) & 1)
|
|
;
|
|
|
|
/* bits 0 to 7 are in 3D5.0D */
|
|
WriteCRT(0x0D, addr);
|
|
/* bits 8 to 15 are in 3D5.0C */
|
|
WriteCRT(0x0C, addr >> 8);
|
|
|
|
/* bit 16 is in 3D5.1E.b5, b7 must be 1. The last is made by
|
|
SetVideoMode */
|
|
temp = ReadCRT(0x1E);
|
|
if (addr & 0x10000)
|
|
temp |= 0x20;
|
|
else
|
|
temp &= 0xDF;
|
|
WriteCRT(0x1E, temp);
|
|
|
|
/* bits 17 and 18 are bits 0 and 1 of 3D5.27 */
|
|
temp = ReadCRT(0x27) & 0xFC;
|
|
WriteCRT(0x27, temp | (addr >> 17));
|
|
|
|
/* Wait a vertical retrace */
|
|
if (waitVRT)
|
|
while (!(inportb(0x3DA) & 8))
|
|
;
|
|
/* Set PEL register */
|
|
outportb(0x3C0, 0x13 | 0x20);
|
|
outportb(0x3C0, PEL);
|
|
}
|
|
|
|
af_scroll_x = x;
|
|
af_scroll_y = y;
|
|
}
|
|
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Sets which buffer is being drawn onto, for use in multi buffering
|
|
systems (not used by Allegro).@p
|
|
I took it from the prototype driver and seems to be totally independent
|
|
of the board.
|
|
|
|
***************************************************************************/
|
|
|
|
void SetActiveBuffer(AF_DRIVER *af, long index)
|
|
{
|
|
if (af->OffscreenOffset) {
|
|
af->OffscreenStartY += af_active_page * af_height;
|
|
af->OffscreenEndY += af_active_page * af_height;
|
|
}
|
|
|
|
af_active_page = index;
|
|
af_y = index * af_height;
|
|
|
|
af->OriginOffset = af_width_bytes * af_height * index;
|
|
|
|
if (af->OffscreenOffset) {
|
|
af->OffscreenStartY -= af_active_page * af_height;
|
|
af->OffscreenEndY -= af_active_page * af_height;
|
|
}
|
|
}
|
|
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Sets which buffer is displayed on the screen, for use in multi buffering
|
|
systems (not used by Allegro).@p
|
|
Copied from the prototype driver.
|
|
|
|
***************************************************************************/
|
|
|
|
void SetVisibleBuffer(AF_DRIVER *af, long index, long waitVRT)
|
|
{
|
|
af_visible_page = index;
|
|
|
|
SetDisplayStart(af, af_scroll_x, af_scroll_y, waitVRT);
|
|
}
|
|
|
|
#define DontBeSillyClearingMoreThanOnes
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Retrieves information about this video mode, returning zero on success
|
|
or -1 if the mode is invalid.
|
|
|
|
***************************************************************************/
|
|
|
|
long GetVideoModeInfo(AF_DRIVER *af, short Mode, AF_MODE_INFO *modeInfo)
|
|
{
|
|
unsigned i;
|
|
int mode = Mode, bpl = 1;
|
|
VideoModeStr *info;
|
|
unsigned sX, sY;
|
|
|
|
/* Report error if the mode is outside the range */
|
|
if ((mode <= 0) || (mode > NumSupportedVideoModes)) return -1;
|
|
|
|
info = SupportedVideoModes[mode - 1];
|
|
|
|
/* clear the structure to zero */
|
|
for (i = 0; i < sizeof(AF_MODE_INFO); i++) ((char *)modeInfo)[i] = 0;
|
|
|
|
/* copy data across from our stored list of mode attributes */
|
|
modeInfo->Attributes = afHaveVirtualScroll | afHaveBankedBuffer |
|
|
afHaveLinearBuffer
|
|
/* Not sure if that's VBE compliant */
|
|
| afHaveHWCursor
|
|
/* TGUI supports ROP3 */
|
|
| afHaveROP2
|
|
/* none of my modes is VGA */
|
|
| afNonVGAMode;
|
|
|
|
sX = info->hDisplay;
|
|
sY = info->vDisplay;
|
|
/* Transfer some bits from my structure */
|
|
/* I doubt the following too are OK because other drivers reports it in
|
|
a different way */
|
|
if (info->flags & DoubleScan) {
|
|
modeInfo->Attributes |= afHaveDoubleScan;
|
|
sY >>= 1;
|
|
}
|
|
if (info->flags & Interlaced) {
|
|
modeInfo->Attributes |= afHaveInterlaced;
|
|
sY <<= 1;
|
|
}
|
|
if (info->flags & HaveAccel2D) modeInfo->Attributes |= afHaveAccel2D;
|
|
|
|
modeInfo->XResolution = sX;
|
|
modeInfo->YResolution = sY;
|
|
switch (ExtractBPP(info->flags)) {
|
|
case is8BPP:
|
|
modeInfo->BitsPerPixel = 8;
|
|
modeInfo->MaxScanLineWidth = 4096;
|
|
#ifndef DontBeSillyClearingMoreThanOnes
|
|
modeInfo->RedMaskSize = 0;
|
|
modeInfo->RedFieldPosition = 0;
|
|
modeInfo->GreenMaskSize = 0;
|
|
modeInfo->GreenFieldPosition = 0;
|
|
modeInfo->BlueMaskSize = 0;
|
|
modeInfo->BlueFieldPosition = 0;
|
|
modeInfo->RsvdMaskSize = 0;
|
|
modeInfo->RsvdFieldPosition = 0;
|
|
#endif
|
|
bpl = 1;
|
|
break;
|
|
case is15BPP:
|
|
modeInfo->BitsPerPixel = 15;
|
|
modeInfo->MaxScanLineWidth = 2048;
|
|
modeInfo->RedMaskSize = 5;
|
|
modeInfo->RedFieldPosition = 10;
|
|
modeInfo->GreenMaskSize = 5;
|
|
modeInfo->GreenFieldPosition = 5;
|
|
modeInfo->BlueMaskSize = 5;
|
|
modeInfo->BlueFieldPosition = 0;
|
|
modeInfo->RsvdMaskSize = 1;
|
|
modeInfo->RsvdFieldPosition = 15;
|
|
bpl = 2;
|
|
break;
|
|
case is16BPP:
|
|
modeInfo->BitsPerPixel = 16;
|
|
modeInfo->MaxScanLineWidth = 2048;
|
|
modeInfo->RedMaskSize = 5;
|
|
modeInfo->RedFieldPosition = 11;
|
|
modeInfo->GreenMaskSize = 6;
|
|
modeInfo->GreenFieldPosition = 5;
|
|
modeInfo->BlueMaskSize = 5;
|
|
modeInfo->BlueFieldPosition = 0;
|
|
modeInfo->RsvdMaskSize = 0;
|
|
modeInfo->RsvdFieldPosition = 0;
|
|
bpl = 2;
|
|
break;
|
|
case is24BPP:
|
|
modeInfo->BitsPerPixel = 24;
|
|
modeInfo->MaxScanLineWidth = 1360;
|
|
modeInfo->RedMaskSize = 8;
|
|
modeInfo->RedFieldPosition = 16;
|
|
modeInfo->GreenMaskSize = 8;
|
|
modeInfo->GreenFieldPosition = 8;
|
|
modeInfo->BlueMaskSize = 8;
|
|
modeInfo->BlueFieldPosition = 0;
|
|
modeInfo->RsvdMaskSize = 0;
|
|
modeInfo->RsvdFieldPosition = 0;
|
|
bpl = 3;
|
|
break;
|
|
}
|
|
|
|
/* available pages of video memory */
|
|
modeInfo->MaxBuffers = AvailableRAM / (info->minBytesPerScan * sY);
|
|
if (modeInfo->MaxBuffers > 1) modeInfo->Attributes |= afHaveMultiBuffer;
|
|
|
|
/* maximum virtual scanline length in both bytes and pixels. How wide
|
|
* this can go will very much depend on the card.
|
|
*/
|
|
/* Here I put the maximun of the chip, if the board doesn't have enough
|
|
RAM that isn't true */
|
|
modeInfo->MaxBytesPerScanLine = 4096;
|
|
|
|
modeInfo->LinBytesPerScanLine = modeInfo->BytesPerScanLine =
|
|
info->minBytesPerScan;
|
|
modeInfo->LinMaxBuffers = modeInfo->BnkMaxBuffers = modeInfo->MaxBuffers;
|
|
|
|
modeInfo->LinRedMaskSize = modeInfo->RedMaskSize;
|
|
modeInfo->LinRedFieldPosition = modeInfo->RedFieldPosition;
|
|
modeInfo->LinGreenMaskSize = modeInfo->GreenMaskSize;
|
|
modeInfo->LinGreenFieldPosition = modeInfo->GreenFieldPosition;
|
|
modeInfo->LinBlueMaskSize = modeInfo->BlueMaskSize;
|
|
modeInfo->LinBlueFieldPosition = modeInfo->BlueFieldPosition;
|
|
modeInfo->LinRsvdMaskSize = modeInfo->RsvdMaskSize;
|
|
modeInfo->LinRsvdFieldPosition = modeInfo->RsvdFieldPosition;
|
|
|
|
/* Shawn says:
|
|
I'm not sure exactly what these should be: Allegro doesn't use them */
|
|
/* Here I put the maximun clock the board can generate according to the
|
|
specifications. The 15/16 bpp modes uses a "character clock divider" I
|
|
think that's what Trident use to call a pixel (%2) and 24 bpp uses %3.
|
|
The manual have a funny bug because they say the other value can be
|
|
used to make %0 (-> infinite) ;-))) */
|
|
modeInfo->MaxPixelClock = 140000000 / bpl;
|
|
#ifndef DontBeSillyClearingMoreThanOnes
|
|
/* Don't have any idea about it */
|
|
modeInfo->VideoCapabilities = 0;
|
|
/* Some boards support zooming nVidia RIVA 128 can do it and I think some
|
|
old Tseng Labs boards too */
|
|
modeInfo->VideoMinXScale = 0;
|
|
modeInfo->VideoMinYScale = 0;
|
|
modeInfo->VideoMaxXScale = 0;
|
|
modeInfo->VideoMaxYScale = 0;
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
/******************** Video Clock calculation algorithm ********************/
|
|
/*****************************************************************************
|
|
|
|
Some info about 9440:
|
|
VClk (Dot clock)
|
|
Main PLL:
|
|
|
|
F=(N+8)/(M+2)*14.31818
|
|
N: 0..121
|
|
M: 0..31
|
|
49.97 < F < 140.03 That means 50..140 MHz
|
|
|
|
Then we have the following dividers:
|
|
%1 and %2 in the PLL.
|
|
%1, %1.5, %2 and %4 in the CRTC
|
|
So we have: %1, %1.5, %2, %3, %4 and %8
|
|
Giving a range: 6.25..140 MHz
|
|
|
|
PClk is the VClk %1, %2 or %3 according to the pixel width (1, 2 or 3 bytes).
|
|
|
|
So as we get the PClk as parameter we must know the video mode to calculate
|
|
the VClk.
|
|
|
|
*****************************************************************************/
|
|
|
|
/* Reference frecuency %1, %1.5, etc. */
|
|
#define NUM_REFS 6
|
|
static
|
|
unsigned fR[]={14318180,9545453,7159090,4772727,3579545,1789773};
|
|
/* Look how fR[3] is the XT clock and fR[4] is the NTSC color sub-carrier */
|
|
|
|
#define ClkErrVal ((unsigned)-1)
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
This routine calculates the closest frecuency to fx that we can achieve
|
|
with the 9440 PLL. The values to program the chip are stored in VClkReg and
|
|
Divider.
|
|
|
|
Return:
|
|
The closest available frecuency or (unsigned)-1 if the value is outside
|
|
the range.
|
|
|
|
***************************************************************************/
|
|
|
|
static
|
|
unsigned FindClosestVClk(unsigned fx, unsigned *VClkReg, unsigned *Divider)
|
|
{
|
|
unsigned M, N, bM = 0, bN = 0, bDiv = 0, fr;
|
|
int div, dif, minDif = 140000000, i;
|
|
unsigned f, bf = 0;
|
|
|
|
/* Reject values clearly outside the range */
|
|
if (fx < 6200000 || fx > 140500000) return ClkErrVal;
|
|
|
|
/* We will try the 6 dividers and the 32 values of M => 192 values */
|
|
for (div = 0; div < NUM_REFS; div++) {
|
|
fr = fR[div];
|
|
/* Search the first M we can use to reduce the values */
|
|
M = (8 * fr) / fx;
|
|
if (M < 2) M = 2;
|
|
for (; M < 34; M++) { /* Solve the equation for N */
|
|
N = (fx * M) / fr;
|
|
/* Reject values outside the range */
|
|
if (N < 8) continue;
|
|
/* If we passed the maximun just pass to the next div */
|
|
if (N > 129) break;
|
|
/* Now try N and N+1 (384 values), N will give a frequency below
|
|
fx and N+1 above fx */
|
|
for (i = 0; i < 2; i++) {
|
|
/* Calculate f */
|
|
f = (N * fr) / M;
|
|
/* Calculate |delta f| */
|
|
dif = f - fx;
|
|
if (dif < 0) dif = -dif;
|
|
/* Store the minimun */
|
|
if (dif < minDif) {
|
|
minDif = dif;
|
|
bM = M;
|
|
bN = N;
|
|
bDiv = div;
|
|
bf = f;
|
|
}
|
|
N++;
|
|
}
|
|
}
|
|
}
|
|
/* Now translate it to register values */
|
|
bM -= 2;
|
|
bN -= 8;
|
|
*VClkReg = bN | (bM << 7);
|
|
switch (bDiv) {
|
|
case 0: *Divider = 2;
|
|
/* %3 */
|
|
case 3: *VClkReg |= 0x1000;
|
|
/* %1.5 */
|
|
case 1: *Divider = VClockDiv1_5 | 2; break;
|
|
/* %4 */
|
|
case 4: *VClkReg |= 0x1000;
|
|
/* %2 */
|
|
case 2: *Divider = VClockDiv2 | 2; break;
|
|
/* %8 */
|
|
case 5:
|
|
*VClkReg |= 0x1000;
|
|
*Divider = VClockDiv4 | 2;
|
|
break;
|
|
}
|
|
return bf;
|
|
}
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Returns the closest Pixel Clock that we can achieve for a desired video
|
|
mode. We must know the mode because the pixel size is determined by the
|
|
mode (8 bpp => 1 byte, 16 bpp => 2 bytes, etc.) and we in fact calculate the
|
|
video clock ("Dot" clock I guess) so we must multiply by the pixel size
|
|
first.@p
|
|
|
|
Returns:
|
|
The closest value available for the board or (unsigned)-1 if the value is
|
|
outside the range.
|
|
|
|
***************************************************************************/
|
|
|
|
long GetClosestPixelClock(AF_DRIVER *af, short mode, unsigned long pixelClock)
|
|
{
|
|
VideoModeStr *info;
|
|
unsigned a1, a2, closest;
|
|
int Bpp;
|
|
|
|
/* Filter the mode number and reject invalid modes */
|
|
mode &= 0x3FF;
|
|
if ((mode <= 0) || (mode > NumSupportedVideoModes)) return ClkErrVal;
|
|
|
|
/* Find the number of bytes per pixel */
|
|
info = SupportedVideoModes[mode - 1];
|
|
Bpp = tBytesPerPixel[ExtractBPP(info->flags)];
|
|
|
|
/* Convert to Video Clock units */
|
|
pixelClock *= Bpp;
|
|
|
|
/* Call the 9440 routine */
|
|
closest = FindClosestVClk(pixelClock, &a1, &a2);
|
|
if (closest == ClkErrVal) return closest;
|
|
|
|
return closest / Bpp;
|
|
}
|
|
|
|
#define afVM_DontPalette 0x80000000
|
|
#define afVM_DontClear 0x8000
|
|
#define afVM_LFB 0x4000
|
|
#define afVM_MultiBuffer 0x2000
|
|
#define afVM_VirtualScrl 0x1000
|
|
#define afVM_UseRefresh 0x0800
|
|
#define afVM_Stereo 0x0400
|
|
|
|
uchar DefaultVGAPalette[768]={
|
|
0x00,0x00,0x00,0x00,0x00,0x2A,0x00,0x2A,0x00,0x00,0x2A,0x2A,0x2A,0x00,0x00,0x2A,
|
|
0x00,0x2A,0x2A,0x15,0x00,0x2A,0x2A,0x2A,0x15,0x15,0x15,0x15,0x15,0x3F,0x15,0x3F,
|
|
0x15,0x15,0x3F,0x3F,0x3F,0x15,0x15,0x3F,0x15,0x3F,0x3F,0x3F,0x15,0x3F,0x3F,0x3F,
|
|
0x00,0x00,0x00,0x05,0x05,0x05,0x08,0x08,0x08,0x0B,0x0B,0x0B,0x0E,0x0E,0x0E,0x11,
|
|
0x11,0x11,0x14,0x14,0x14,0x18,0x18,0x18,0x1C,0x1C,0x1C,0x20,0x20,0x20,0x24,0x24,
|
|
0x24,0x28,0x28,0x28,0x2D,0x2D,0x2D,0x32,0x32,0x32,0x38,0x38,0x38,0x3F,0x3F,0x3F,
|
|
0x00,0x00,0x3F,0x10,0x00,0x3F,0x1F,0x00,0x3F,0x2F,0x00,0x3F,0x3F,0x00,0x3F,0x3F,
|
|
0x00,0x2F,0x3F,0x00,0x1F,0x3F,0x00,0x10,0x3F,0x00,0x00,0x3F,0x10,0x00,0x3F,0x1F,
|
|
0x00,0x3F,0x2F,0x00,0x3F,0x3F,0x00,0x2F,0x3F,0x00,0x1F,0x3F,0x00,0x10,0x3F,0x00,
|
|
0x00,0x3F,0x00,0x00,0x3F,0x10,0x00,0x3F,0x1F,0x00,0x3F,0x2F,0x00,0x3F,0x3F,0x00,
|
|
0x2F,0x3F,0x00,0x1F,0x3F,0x00,0x10,0x3F,0x1F,0x1F,0x3F,0x27,0x1F,0x3F,0x2F,0x1F,
|
|
0x3F,0x37,0x1F,0x3F,0x3F,0x1F,0x3F,0x3F,0x1F,0x37,0x3F,0x1F,0x2F,0x3F,0x1F,0x27,
|
|
0x3F,0x1F,0x1F,0x3F,0x27,0x1F,0x3F,0x2F,0x1F,0x3F,0x37,0x1F,0x3F,0x3F,0x1F,0x37,
|
|
0x3F,0x1F,0x2F,0x3F,0x1F,0x27,0x3F,0x1F,0x1F,0x3F,0x1F,0x1F,0x3F,0x27,0x1F,0x3F,
|
|
0x2F,0x1F,0x3F,0x37,0x1F,0x3F,0x3F,0x1F,0x37,0x3F,0x1F,0x2F,0x3F,0x1F,0x27,0x3F,
|
|
0x2D,0x2D,0x3F,0x31,0x2D,0x3F,0x36,0x2D,0x3F,0x3A,0x2D,0x3F,0x3F,0x2D,0x3F,0x3F,
|
|
0x2D,0x3A,0x3F,0x2D,0x36,0x3F,0x2D,0x31,0x3F,0x2D,0x2D,0x3F,0x31,0x2D,0x3F,0x36,
|
|
0x2D,0x3F,0x3A,0x2D,0x3F,0x3F,0x2D,0x3A,0x3F,0x2D,0x36,0x3F,0x2D,0x31,0x3F,0x2D,
|
|
0x2D,0x3F,0x2D,0x2D,0x3F,0x31,0x2D,0x3F,0x36,0x2D,0x3F,0x3A,0x2D,0x3F,0x3F,0x2D,
|
|
0x3A,0x3F,0x2D,0x36,0x3F,0x2D,0x31,0x3F,0x00,0x00,0x1C,0x07,0x00,0x1C,0x0E,0x00,
|
|
0x1C,0x15,0x00,0x1C,0x1C,0x00,0x1C,0x1C,0x00,0x15,0x1C,0x00,0x0E,0x1C,0x00,0x07,
|
|
0x1C,0x00,0x00,0x1C,0x07,0x00,0x1C,0x0E,0x00,0x1C,0x15,0x00,0x1C,0x1C,0x00,0x15,
|
|
0x1C,0x00,0x0E,0x1C,0x00,0x07,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x07,0x00,0x1C,
|
|
0x0E,0x00,0x1C,0x15,0x00,0x1C,0x1C,0x00,0x15,0x1C,0x00,0x0E,0x1C,0x00,0x07,0x1C,
|
|
0x0E,0x0E,0x1C,0x11,0x0E,0x1C,0x15,0x0E,0x1C,0x18,0x0E,0x1C,0x1C,0x0E,0x1C,0x1C,
|
|
0x0E,0x18,0x1C,0x0E,0x15,0x1C,0x0E,0x11,0x1C,0x0E,0x0E,0x1C,0x11,0x0E,0x1C,0x15,
|
|
0x0E,0x1C,0x18,0x0E,0x1C,0x1C,0x0E,0x18,0x1C,0x0E,0x15,0x1C,0x0E,0x11,0x1C,0x0E,
|
|
0x0E,0x1C,0x0E,0x0E,0x1C,0x11,0x0E,0x1C,0x15,0x0E,0x1C,0x18,0x0E,0x1C,0x1C,0x0E,
|
|
0x18,0x1C,0x0E,0x15,0x1C,0x0E,0x11,0x1C,0x14,0x14,0x1C,0x16,0x14,0x1C,0x18,0x14,
|
|
0x1C,0x1A,0x14,0x1C,0x1C,0x14,0x1C,0x1C,0x14,0x1A,0x1C,0x14,0x18,0x1C,0x14,0x16,
|
|
0x1C,0x14,0x14,0x1C,0x16,0x14,0x1C,0x18,0x14,0x1C,0x1A,0x14,0x1C,0x1C,0x14,0x1A,
|
|
0x1C,0x14,0x18,0x1C,0x14,0x16,0x1C,0x14,0x14,0x1C,0x14,0x14,0x1C,0x16,0x14,0x1C,
|
|
0x18,0x14,0x1C,0x1A,0x14,0x1C,0x1C,0x14,0x1A,0x1C,0x14,0x18,0x1C,0x14,0x16,0x1C,
|
|
0x00,0x00,0x10,0x04,0x00,0x10,0x08,0x00,0x10,0x0C,0x00,0x10,0x10,0x00,0x10,0x10,
|
|
0x00,0x0C,0x10,0x00,0x08,0x10,0x00,0x04,0x10,0x00,0x00,0x10,0x04,0x00,0x10,0x08,
|
|
0x00,0x10,0x0C,0x00,0x10,0x10,0x00,0x0C,0x10,0x00,0x08,0x10,0x00,0x04,0x10,0x00,
|
|
0x00,0x10,0x00,0x00,0x10,0x04,0x00,0x10,0x08,0x00,0x10,0x0C,0x00,0x10,0x10,0x00,
|
|
0x0C,0x10,0x00,0x08,0x10,0x00,0x04,0x10,0x08,0x08,0x10,0x0A,0x08,0x10,0x0C,0x08,
|
|
0x10,0x0E,0x08,0x10,0x10,0x08,0x10,0x10,0x08,0x0E,0x10,0x08,0x0C,0x10,0x08,0x0A,
|
|
0x10,0x08,0x08,0x10,0x0A,0x08,0x10,0x0C,0x08,0x10,0x0E,0x08,0x10,0x10,0x08,0x0E,
|
|
0x10,0x08,0x0C,0x10,0x08,0x0A,0x10,0x08,0x08,0x10,0x08,0x08,0x10,0x0A,0x08,0x10,
|
|
0x0C,0x08,0x10,0x0E,0x08,0x10,0x10,0x08,0x0E,0x10,0x08,0x0C,0x10,0x08,0x0A,0x10,
|
|
0x0B,0x0B,0x10,0x0C,0x0B,0x10,0x0D,0x0B,0x10,0x0F,0x0B,0x10,0x10,0x0B,0x10,0x10,
|
|
0x0B,0x0F,0x10,0x0B,0x0D,0x10,0x0B,0x0C,0x10,0x0B,0x0B,0x10,0x0C,0x0B,0x10,0x0D,
|
|
0x0B,0x10,0x0F,0x0B,0x10,0x10,0x0B,0x0F,0x10,0x0B,0x0D,0x10,0x0B,0x0C,0x10,0x0B,
|
|
0x0B,0x10,0x0B,0x0B,0x10,0x0C,0x0B,0x10,0x0D,0x0B,0x10,0x0F,0x0B,0x10,0x10,0x0B,
|
|
0x0F,0x10,0x0B,0x0D,0x10,0x0B,0x0C,0x10,0x03,0x00,0x0F,0x02,0x00,0x0C,0x02,0x00,
|
|
0x09,0x01,0x00,0x07,0x01,0x00,0x04,0x00,0x00,0x02,0x00,0x00,0x00,0x3F,0x3F,0x3F};
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Sets the video mode. This function have various features, be careful.@p
|
|
Mode is a 32 bits value, and not 16 bits as the first drafts propposed.
|
|
Because a some nasty reasons isn't just a mode number but some sort of flags
|
|
plus mode number. The lower 10 bits are the video mode number the rest of
|
|
the bits have the following meaning:@p
|
|
|
|
0x8000 = don't clear video memory.@*
|
|
0x4000 = enable linear framebuffer.@*
|
|
0x2000 = enable multi buffering.@*
|
|
0x1000 = enable virtual scrolling.@*
|
|
0x0800 = use refresh rate control.@*
|
|
0x0400 = use hardware stereo.@p
|
|
|
|
Most of them are self-explanatory, and others aren't very clear yet.@p
|
|
The virtual screen size is requested by the virtualX/Y pair the driver will
|
|
set a screen of at least this size, if isn't posible will return error. Note
|
|
that the actual size could be greater. For this reason bytesPerLine is filled
|
|
with the actual X virtual size (stride?).@p
|
|
You can request more than one buffer indicating it in numBuffers, if the RAM
|
|
isn't enough the driver will return error.@p
|
|
Perhaps the hardest parameter to understand is crtc. This parameter provides
|
|
a mechanism to allow setting the refresh rate and centering the screen. The
|
|
mechanism is incomplet and SciTech people complements it with OEM extentions,
|
|
I asked to make these extentions official and Kendall said he will consider
|
|
it for Nucleus. Anyways, this pointer will be used by the driver if you use
|
|
the 0x0800 flag, the members of the structure are:@p
|
|
|
|
unsigned short HorizontalTotal: Total pixels, visible and not visible.@*
|
|
unsigned short HorizontalSyncStart: Pixel where the horizontal sync pulse
|
|
starts.@*
|
|
unsigned short HorizontalSyncEnd: End of the pulse.@*
|
|
unsigned short VerticalTotal: Total lines, visible and not.@*
|
|
unsigned short VerticalSyncStart: Vertical sync pulse start.@*
|
|
unsigned short VerticalSyncEnd: End of the pulse.@*
|
|
unsigned char Flags: Various flags see below.@*
|
|
unsigned int PixelClock: Desired pixel clock, the driver will use the
|
|
closest available so you must check it with GetClosestPixelClock.
|
|
@x{GetClosestPixelClock}.@*
|
|
unsigned short RefreshRate: Just ignore it is for very old controllers that
|
|
have some specific crtc register values for each mode.@*
|
|
unsigned short NumBuffers: That's here only for compatibility issues related
|
|
to VBE/AF 1.0.@p
|
|
|
|
The possible flags are:@p
|
|
|
|
afDoubleScan (0x0001) Enable double scanned mode.@*
|
|
afInterlaced (0x0002) Enable interlaced mode.@*
|
|
afHSyncNeg (0x0004) Horizontal sync is negative.@*
|
|
afVSyncNeg (0x0008) Vertical sync is negative.@p
|
|
|
|
As you can see only the X/Y resolution is set by the driver and you control
|
|
all the rest.@p
|
|
To use it you must first find information about the monitor (asking the user
|
|
or using DDC?), then calculate the total and sync positions with the VESA
|
|
GTF formula and the aid of GetClosestPixelClock and finally pass these values
|
|
to the driver.@p
|
|
|
|
Important:@p
|
|
1) I don't care about LFB that's on all the time.@*
|
|
2) I expanded the short mode to unsigned mode because MGL 4.05 does it.@*
|
|
3) I added a propietary flag: 0x80000000: Don't set the palette. I think it
|
|
will be replaced by some OEM extention, avoid using it.@p
|
|
|
|
***************************************************************************/
|
|
|
|
long SetVideoMode(AF_DRIVER *af, short mode, long virtualX, long virtualY,
|
|
long *bytesPerLine, int numBuffers, AF_CRTCInfo *crtc)
|
|
{
|
|
int clear = ((mode & afVM_DontClear) == 0);
|
|
int putPal = ((mode & afVM_DontPalette) == 0);
|
|
int CRTCValid = ((mode & afVM_UseRefresh) != 0) && crtc;
|
|
unsigned used_vram, af_width, sX, sY;
|
|
int bpl, nbpp, Bpp;
|
|
VideoModeStr *info, byApp;
|
|
|
|
/* reject anything with hardware stereo */
|
|
if (mode & afVM_Stereo) return -1;
|
|
|
|
afCurrentMode = mode;
|
|
/* mask off the other flag bits */
|
|
mode &= 0x3FF;
|
|
|
|
if ((mode <= 0) || (mode > NumSupportedVideoModes)) return -1;
|
|
|
|
info = SupportedVideoModes[--mode];
|
|
|
|
sX = info->hDisplay;
|
|
sY = info->vDisplay;
|
|
if (info->flags & DoubleScan) sY >>= 1;
|
|
if (info->flags & Interlaced) sY <<= 1;
|
|
|
|
/* Now choose the right virtual width */
|
|
nbpp = ExtractBPP(info->flags);
|
|
Bpp = tBytesPerPixel[nbpp];
|
|
bpl = GetBestPitchFor(MAX(virtualX, (long)sX), Bpp);
|
|
if (bpl < 0) return -1;
|
|
*bytesPerLine = bpl;
|
|
|
|
/* store info about the current mode */
|
|
af_bpp = tBitsPerPixel[nbpp];
|
|
af_bytespp = Bpp;
|
|
af_width_bytes = *bytesPerLine;
|
|
af_height = MAX((long)sY, virtualY);
|
|
af_visible_page = 0;
|
|
af_active_page = 0;
|
|
af_scroll_x = 0;
|
|
af_scroll_y = 0;
|
|
af_y = 0;
|
|
af_width = bpl / Bpp;
|
|
afCurrentBank = 0;
|
|
|
|
/* return framebuffer dimensions to the application */
|
|
af->BufferEndX = af_width_bytes / af_bytespp - 1;
|
|
af->BufferEndY = af_height - 1;
|
|
af->OriginOffset = 0;
|
|
|
|
used_vram = af_width_bytes * af_height * numBuffers;
|
|
|
|
if (used_vram > AvailableRAM) return -1;
|
|
|
|
if (AvailableRAM - used_vram >= af_width_bytes) {
|
|
af->OffscreenOffset = used_vram;
|
|
af->OffscreenStartY = af_height * numBuffers;
|
|
af->OffscreenEndY = AvailableRAM / af_width_bytes - 1;
|
|
} else {
|
|
af->OffscreenOffset = 0;
|
|
af->OffscreenStartY = 0;
|
|
af->OffscreenEndY = 0;
|
|
}
|
|
|
|
/* Set the fore/back mixing to the default values */
|
|
UsesBackMix = DontMakeBackMix = 0;
|
|
BackMix = LineForegroundMix = CurrentForegroundMix = ROP_P;
|
|
LineForegroundMixToS = ROP_S;
|
|
|
|
/* Look if the application is suggesting the video mode refresh rate */
|
|
if (CRTCValid) {
|
|
unsigned closest, VClk, Divider;
|
|
|
|
byApp.minBytesPerScan = info->minBytesPerScan;
|
|
/* Copy the values from the CRTC structure */
|
|
byApp.hDisplay = sX;
|
|
byApp.hTotal = crtc->HorizontalTotal;
|
|
byApp.hSyncStart = crtc->HorizontalSyncStart;
|
|
byApp.hSyncEnd = crtc->HorizontalSyncEnd;
|
|
byApp.vDisplay = sY;
|
|
byApp.vTotal = crtc->VerticalTotal;
|
|
byApp.vSyncStart = crtc->VerticalSyncStart;
|
|
byApp.vSyncEnd = crtc->VerticalSyncEnd;
|
|
byApp.flags = info->flags & InternalMask;
|
|
if (crtc->Flags & afDoubleScan) {
|
|
byApp.flags |= DoubleScan;
|
|
byApp.vDisplay <<= 1;
|
|
}
|
|
if (crtc->Flags & afInterlaced) {
|
|
byApp.flags |= Interlaced;
|
|
byApp.vDisplay >>= 1;
|
|
}
|
|
if (crtc->Flags & afHSyncNeg) byApp.flags |= NHSync;
|
|
if (crtc->Flags & afVSyncNeg) byApp.flags |= NVSync;
|
|
closest = FindClosestVClk(crtc->PixelClock * Bpp, &VClk, &Divider);
|
|
if (closest == ClkErrVal) return -1;
|
|
byApp.ClockType = Divider;
|
|
byApp.ClockValLow = VClk;
|
|
byApp.ClockValHigh = VClk >> 8;
|
|
/* The following values are filled by the app. and ignored here
|
|
crtc->RefreshRate=closest*100/byApp.vTotal/byApp.hTotal;
|
|
crtc->NumBuffers=AvailableRAM/(info->minBytesPerScan*sY);*/
|
|
SetVideoModeH(&byApp, af_width, af_bpp);
|
|
} else
|
|
SetVideoModeH(info, af_width, af_bpp);
|
|
|
|
/* 8 bpp palette */
|
|
if (af_bpp == 8 && putPal) RPF_SetPalRange(DefaultVGAPalette, 0, 256);
|
|
|
|
/* All the routines sets it only if change so we must start we a known
|
|
state or it could hang */
|
|
SetForegroundMix(CurrentForegroundMix);
|
|
|
|
IsAceleratorOn = info->flags & HaveAccel2D ? 1 : 0;
|
|
if (clear) {
|
|
if (IsAceleratorOn)
|
|
/* If we have the accelerator clean the screen without the CPU */
|
|
DrawRawRect(0, 0, 0, af_width - 1, af_height - 1);
|
|
else {
|
|
unsigned i;
|
|
for (i = used_vram / 4; i; --i) Screenl[i] = 0;
|
|
Screenl[i] = 0;
|
|
}
|
|
}
|
|
|
|
/* Hardware cursor initialization */
|
|
/* Shape offset in VRAM */
|
|
WriteCRT(0x44, CursorPat);
|
|
WriteCRT(0x45, CursorPat >> 8);
|
|
/* Offset inside the shape (X,Y) */
|
|
WriteCRT(0x46, 0);
|
|
WriteCRT(0x47, 0);
|
|
/* In double scan modes the cursor must be adjusted */
|
|
HaveDoubleScan = info->flags & DoubleScan ? 1 : 0;
|
|
|
|
if (IsAceleratorOn) {
|
|
af->DrawScan = DrawScan;
|
|
af->DrawScanList = DrawScanList;
|
|
af->DrawPattScan = DrawPattScan;
|
|
af->DrawPattScanList = DrawPattScanList;
|
|
af->DrawColorPattScan = DrawColorPattScan;
|
|
af->DrawColorPattScanList = DrawColorPattScanList;
|
|
af->DrawRect = DrawRect;
|
|
af->DrawPattRect = DrawPattRect;
|
|
af->DrawColorPattRect = DrawColorPattRect;
|
|
af->DrawLine = DrawLine;
|
|
af->DrawTrap = DrawTrap;
|
|
/* Dotted (Stipple) lines */
|
|
/* I'm not sure about the behavior of these functions, I just
|
|
implemented the functionallities found in TGUI9440. I guess they are the
|
|
same needed for the driver, after all Trident was in the VBE/AF desing */
|
|
af->SetLineStipple = SetLineStipple;
|
|
af->SetLineStippleCount = SetLineStippleCount;
|
|
af->DrawStippleLine = DrawStippleLine;
|
|
af->BitBlt = BitBlt;
|
|
af->BitBltSys = BitBltSys;
|
|
af->SrcTransBlt = SrcTransBlt;
|
|
af->SrcTransBltSys = SrcTransBltSys;
|
|
af->PutMonoImage = PutMonoImage;
|
|
|
|
/* Routines to control the access to the video ram */
|
|
af->WaitTillIdle = WaitTillIdle;
|
|
/* I'm not sure about these 2, seems that I don't need it by Kendall
|
|
says in an e-mail that normally EnableDirectAccess is the same as
|
|
WaitTillIdle so I implemented it in this way */
|
|
/* I commented it because VBE/AF 1.0 draft says they are optional and
|
|
WaitTillIdle requered, so if I provide WaitTillIdle must be enough.
|
|
af->EnableDirectAccess = EnableDirectAccess;
|
|
af->DisableDirectAccess = DisableDirectAccess;*/
|
|
|
|
} else { /* 24 bpp doesn't have it :-( */
|
|
af->DrawScan = NULL;
|
|
af->DrawScanList = NULL;
|
|
af->DrawPattScan = NULL;
|
|
af->DrawPattScanList = NULL;
|
|
af->DrawRect = NULL;
|
|
af->DrawPattRect = NULL;
|
|
af->DrawLine = NULL;
|
|
af->BitBlt = NULL;
|
|
af->DrawColorPattScan = NULL;
|
|
af->DrawColorPattScanList = NULL;
|
|
af->DrawColorPattRect = NULL;
|
|
af->SetLineStipple = NULL;
|
|
af->SetLineStippleCount = NULL;
|
|
af->DrawStippleLine = NULL;
|
|
af->BitBlt = NULL;
|
|
af->BitBltSys = NULL;
|
|
af->SrcTransBlt = NULL;
|
|
af->SrcTransBltSys = NULL;
|
|
af->PutMonoImage = NULL;
|
|
af->DrawTrap = NULL;
|
|
af->WaitTillIdle = NULL;
|
|
}
|
|
|
|
/* Some GER values */
|
|
/* Patterned lines: Pattern cleared, counters reseted */
|
|
Putl(0x44, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef INCLUDE_OLD_INERTIA_STUFF
|
|
#include "oldinert.h"
|
|
#endif
|
|
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Returns to text mode, shutting down the accelerator hardware.
|
|
|
|
***************************************************************************/
|
|
|
|
void RestoreTextMode(AF_DRIVER *af)
|
|
{
|
|
SetTextModeVGA( );
|
|
}
|
|
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Provides direct access to the video RAM. That's needed for boards where
|
|
the accelerator blocks the use of the video RAM.@p
|
|
TGUI9440 does it only during the Blit operations so in my case I simply
|
|
do a wait until de Graphics Engine finished your job. Note that this routine
|
|
is here just for testing because isn't needed and isn't reported.
|
|
|
|
Example:
|
|
|
|
EnableDirectAccess(af);
|
|
.... Draw to the screen ....
|
|
DisableDirectAccess(af);
|
|
|
|
***************************************************************************/
|
|
|
|
void EnableDirectAccess(AF_DRIVER *af)
|
|
{
|
|
WaitGE( );
|
|
}
|
|
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Disables the direct access to the video RAM. That's needed for boards
|
|
where the accelerator blocks the use of the video RAM.@p
|
|
TGUI9440 does it only during the Blit operations so in my case this
|
|
function does nothing. Note that this routine is here just for testing
|
|
because isn't needed and isn't reported.
|
|
|
|
***************************************************************************/
|
|
|
|
void DisableDirectAccess(AF_DRIVER *af)
|
|
{
|
|
}
|
|
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Waits until the accelerator finished your job. That's a very important
|
|
function. Suppose you want to draw over a rectangle made with DrawRect, how
|
|
can you be sure you won't draw under it? Waiting until the accelerator
|
|
finished your job.@p
|
|
What I don't fully understand is the need of both:
|
|
Enable/DisableDirectAccess and WaitTillIdle. I saw an e-mail by Kendall
|
|
tallking about it.@p
|
|
The TGUI9440 waits until the Graphic Engine finished all the jobs.
|
|
|
|
***************************************************************************/
|
|
|
|
void WaitTillIdle(AF_DRIVER *af)
|
|
{
|
|
WaitGE( );
|
|
}
|
|
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
Vendor-specific extension hook: we don't provide any.
|
|
|
|
***************************************************************************/
|
|
|
|
int ExtStub()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
The first thing ever to be called after our code has been relocated.
|
|
This is in charge of filling in the driver header with all the required
|
|
information and function pointers. We do not yet have access to the
|
|
video memory, so we can't talk directly to the card.
|
|
|
|
***************************************************************************/
|
|
|
|
int SetupDriver(AF_DRIVER *af)
|
|
{
|
|
int bus_id;
|
|
|
|
/* It looks silly: I must have access to the PCI registers! */
|
|
if (!FindPCIDevice(af->PCIDeviceID, af->PCIVendorID, 0, &bus_id)) return -1;
|
|
|
|
af->AvailableModes = SupportedVideoModesNums;
|
|
|
|
af->Attributes = afHaveMultiBuffer | afHaveVirtualScroll |
|
|
afHaveBankedBuffer | afHaveLinearBuffer | afHaveAccel2D |
|
|
afHaveHWCursor | afHaveROP2;
|
|
|
|
af->IOPortsTable = PortsTable;
|
|
|
|
/* 64Kb banking area */
|
|
af->BankedBasePtr = 0xA0000;
|
|
af->BankSize = 64;
|
|
|
|
af->LinearBasePtr = PCIReadLong(bus_id, 0x10);
|
|
/* TGUI 9440 ever uses a 2Mb aperture */
|
|
af->LinearSize = 2048;
|
|
|
|
/* 64Kb text mode area, I map the GER here */
|
|
af->IOMemoryBase[0] = 0xB0000;
|
|
af->IOMemoryLen[0] = 64;
|
|
/* That's the mapping for the GER, but as I need more space to
|
|
restore the text mode I simply map the whole text mode region */
|
|
/*af->IOMemoryBase[0]=0xB7F00;
|
|
af->IOMemoryLen[0]=1;
|
|
af->IOMemoryBase[1]=0xBFF00;
|
|
af->IOMemoryLen[1]=1;*/
|
|
|
|
/* set up driver functions */
|
|
af->SetBank32 = SetBank32;
|
|
af->SetBank32Len = (long)SetBank32End - (long)SetBank32;
|
|
|
|
af->SupplementalExt = ExtStub;
|
|
|
|
af->GetVideoModeInfo = GetVideoModeInfo;
|
|
af->SetVideoMode = SetVideoMode;
|
|
af->RestoreTextMode = RestoreTextMode;
|
|
|
|
af->SetDisplayStart = SetDisplayStart;
|
|
af->SetActiveBuffer = SetActiveBuffer;
|
|
af->SetVisibleBuffer = SetVisibleBuffer;
|
|
af->GetDisplayStartStatus = GetDisplayStartStatus;
|
|
af->SetBank = SetBank;
|
|
|
|
af->SetPaletteData = SetPaletteData;
|
|
|
|
af->SetMix = SetMix;
|
|
af->Set8x8MonoPattern = Set8x8MonoPattern;
|
|
af->Set8x8ColorPattern = Set8x8ColorPattern;
|
|
af->Use8x8ColorPattern = Use8x8ColorPattern;
|
|
|
|
af->SetCursor = SetCursor;
|
|
af->SetCursorPos = SetCursorPos;
|
|
af->SetCursorColor = SetCursorColor;
|
|
af->ShowCursor = ShowCursor;
|
|
|
|
af->GetClosestPixelClock = GetClosestPixelClock;
|
|
|
|
#ifdef INCLUDE_OLD_INERTIA_STUFF
|
|
/* Inertia stuff */
|
|
af->GetConfigInfo = GetConfigInfo;
|
|
af->GetCurrentMode = GetCurrentMode;
|
|
af->SetVSyncWidth = SetVSyncWidth;
|
|
af->GetVSyncWidth = GetVSyncWidth;
|
|
af->GetBank = GetBank;
|
|
af->GetVisibleBuffer = GetVisibleBuffer;
|
|
af->GetDisplayStart = GetDisplayStart;
|
|
af->SetDisplayStartAddr = SetDisplayStartAddr;
|
|
af->IsVSync = IsVSync;
|
|
af->WaitVSync = WaitVSync;
|
|
af->GetActiveBuffer = GetActiveBuffer;
|
|
af->IsIdle = IsIdle;
|
|
#endif
|
|
|
|
/* ToDo
|
|
af->SaveRestoreState = NULL;
|
|
*/
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**[txh]********************************************************************
|
|
|
|
Description:
|
|
The second thing to be called during the init process, after the
|
|
application has mapped all the memory and I/O resources we need. This is in
|
|
charge of finding the card, returning 0 on success or -1 to abort.
|
|
|
|
***************************************************************************/
|
|
|
|
int InitDriver(AF_DRIVER *af)
|
|
{
|
|
int i;
|
|
|
|
MMIOBASE = (unsigned)(af->IOMemMaps[0]) + 0x7F00;
|
|
linearAddress = (unsigned long)af->LinearMem;
|
|
bankedAddress = (unsigned long)af->BankedMem;
|
|
TextModeMemory = (unsigned *)((unsigned)(af->IOMemMaps[0]) + 0x8000);
|
|
/* Now I can access the linear buffer and all the registers */
|
|
CaptureSVGAStart( );
|
|
/* Find the amount of installed memory */
|
|
AvailableRAM = TestMemory( );
|
|
|
|
/* Normalize the memory size, I had problem with intermediate sizes looks
|
|
like is impossible to detect 1.25 Mb. Trident's BIOS only reports 256K,
|
|
512K, 1M or 2Mb it looks like a limitation of what we can detect */
|
|
if (AvailableRAM >= (1 << 21))
|
|
AvailableRAM = 1 << 21;
|
|
else if (AvailableRAM >= (1 << 20))
|
|
AvailableRAM = 1 << 20;
|
|
else if (AvailableRAM >= (1 << 19))
|
|
AvailableRAM = 1 << 19;
|
|
else if (AvailableRAM >= (1 << 18))
|
|
AvailableRAM = 1 << 18;
|
|
else
|
|
return -1;
|
|
|
|
af->TotalMemory = AvailableRAM / 1024; /* In Kb */
|
|
|
|
/* Reserve 2Kb of memory for patterns and harware cursor */
|
|
/* Monochromatic pattern */
|
|
/* I use 128 bytes aligment because in 16bpp that's required */
|
|
AvailableRAM -= 128;
|
|
pMonoPattern = linearAddress + AvailableRAM;
|
|
MonoPattern = AvailableRAM >> 6;
|
|
AvailableRAM -= 128;
|
|
pInvMonoPattern = linearAddress + AvailableRAM;
|
|
InvMonoPattern = AvailableRAM >> 6;
|
|
/* Hardware Cursor */
|
|
/* 32x32 (size) * 2 (planes) / 8 (packed) = 256 but 1K aligned */
|
|
AvailableRAM -= 256 + 512;
|
|
pCursorPat = linearAddress + AvailableRAM;
|
|
CursorPat = AvailableRAM >> 10;
|
|
/* 8 patterns of 8x8x2 bytes */
|
|
for (i = 0; i < 8; i++) {
|
|
AvailableRAM -= 128;
|
|
pColorPatterns[i] = linearAddress + AvailableRAM;
|
|
ColorPatterns[i] = AvailableRAM >> 6;
|
|
}
|
|
SelectedColorPattern = ColorPatterns[0];
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* FreeBEX:
|
|
* Returns an interface structure for the requested FreeBE/AF extension.
|
|
*/
|
|
void *FreeBEX(AF_DRIVER *af, unsigned long id)
|
|
{
|
|
switch (id) {
|
|
default: return NULL;
|
|
}
|
|
}
|