Browse Source

* Added accelerated drawing functions for modes with 4 bits per pixel

sg 25 years ago
parent
commit
a662bff34d
2 changed files with 484 additions and 13 deletions
  1. 57 13
      rtl/linux/vgagraph.inc
  2. 427 0
      rtl/linux/vgagraph16.inc

+ 57 - 13
rtl/linux/vgagraph.inc

@@ -17,6 +17,16 @@
   const
    InternalDriverName = 'LinuxVGA';
 
+
+  type
+    PByte = ^Byte;
+    PLongInt = ^LongInt;
+
+    PByteArray = ^TByteArray;
+    TByteArray = array [0..MAXINT - 1] of Byte;
+
+
+
 { ---------------------------------------------------------------------
    SVGA bindings.
 
@@ -153,11 +163,26 @@ var
  Function vga_drawline(x1, y1, x2, y2: Longint): Longint; cdecl;external;
  function vga_screenoff: Longint; Cdecl; External;
  function vga_screenon: Longint;  Cdecl; External;
+ function vga_getgraphmem: PByteArray; cdecl; external;
 
 { ---------------------------------------------------------------------
     Required procedures
   ---------------------------------------------------------------------}
 
+{$INCLUDE vgagraph16.inc}	// Include graphic functions for 16 colours modes
+
+var
+  LastColor: Integer;	{Cache the last set color to improve speed}
+
+procedure SetEGAColor(color: Integer);
+begin
+  if color <> LastColor then begin
+    LastColor := color;
+    vga_setegacolor(color);
+  end;
+end;
+
+
 procedure libvga_savevideostate;
 begin
 end;
@@ -192,6 +217,7 @@ Var Nrcolors : Longint;
 begin
   vga_setmode(IntCurrentMode);
   vga_screenon;
+  VidMem := vga_getgraphmem;
   nrColors:=vga_getcolors;
   if (nrColors=16) or (nrcolors=256) then
     InitColors;
@@ -246,14 +272,14 @@ begin
   else
     Color:=CurrentColor;
   end;
-  vga_setegaColor(Color);
+  SetEGAColor(Color);
   vga_drawpixel(x, y);
 end;
 
 procedure libvga_putpixelproc(X,Y: Integer; Color: Word);
 begin
   If Not ClipCoords(X,Y) Then exit;
-  vga_setegaColor(Color);
+  SetEGAColor(Color);
   vga_drawpixel(x, y);
 end;
 
@@ -268,7 +294,7 @@ procedure libvga_clrviewproc;
 Var I,Xmax : longint;
 
 begin
-  vga_SetegaColor(CurrentBkColor);
+  SetEGAColor(CurrentBkColor);
   Xmax:=StartXViewPort+ViewWidth-1;
   For i:=StartYViewPort to StartYViewPort+ViewHeight-1 do
     vga_drawline(StartXViewPort,I,Xmax,I);
@@ -410,7 +436,7 @@ end;
            begin
            ModeNumber:=I;
            ModeName:=ModeNames[i];
-           // Pretend we're VGA always.
+           // Pretend we are VGA always.
            DriverNumber := VGA;
            MaxX:=ModeInfo.Width;
            MaxY:=ModeInfo.height;
@@ -418,24 +444,39 @@ end;
            PaletteSize := MaxColor;
            HardwarePages := 0;
            // necessary hooks ...
-           DirectPutPixel := @libvga_DirectPixelProc;
-           GetPixel       := @Libvga_GetPixelProc;
-           PutPixel       := @libvga_PutPixelProc;
+	   if (MaxColor = 16) and (LongInt(MaxX) * LongInt(MaxY) < 65536*4*2) then
+	   begin
+	     // Use optimized graphics routines for 4 bit EGA/VGA modes
+	     ScrWidth := MaxX div 8;
+             DirectPutPixel := @DirectPutPixel16;
+	     PutPixel := @PutPixel16;
+    	     GetPixel := @GetPixel16;
+             HLine := @HLine16;
+    	     VLine := @VLine16;
+             GetScanLine := @GetScanLine16;
+	   end
+	   else
+	   begin
+             DirectPutPixel := @libvga_DirectPixelProc;
+             GetPixel       := @libvga_GetPixelProc;
+             PutPixel       := @libvga_PutPixelProc;
+	     {Can be added later:
+	     HLine          := @libvga_HLineProc;
+             VLine          := @libvga_VLineProc;
+             GetScanLine    := @libvga_GetScanLineProc;}
+           end;
            SetRGBPalette  := @libvga_SetRGBPaletteProc;
            GetRGBPalette  := @libvga_GetRGBPaletteProc;
-           ClearViewPort  := libvga_ClrViewProc;
-           PutImage       := @Libvga_PutImageProc;
+           ClearViewPort  := @libvga_ClrViewProc;
+           PutImage       := @libvga_PutImageProc;
            GetImage       := @libvga_GetImageProc;
            ImageSize      := @libvga_ImageSizeProc;
            { Add later maybe ?
            SetVisualPage  := SetVisualPageProc;
            SetActivePage  := SetActivePageProc;
-           GetScanLine    := @libvga_GetScanLineProc;
            Line           := @libvga_LineProc;
            InternalEllipse:= @libvga_EllipseProc;
            PatternLine    := @libvga_PatternLineProc;
-           HLine          := @libvga_HLineProc;
-           VLine          := @libvga_VLineProc;
            }
            InitMode       := @libvga_InitModeProc;
            end;
@@ -446,7 +487,10 @@ end;
 
 {
   $Log$
-  Revision 1.9  2000-02-27 14:41:25  peter
+  Revision 1.10  2000-03-17 13:30:35  sg
+  * Added accelerated drawing functions for modes with 4 bits per pixel
+
+  Revision 1.9  2000/02/27 14:41:25  peter
     * removed warnings/notes
 
   Revision 1.8  2000/02/06 11:26:45  sg

+ 427 - 0
rtl/linux/vgagraph16.inc

@@ -0,0 +1,427 @@
+ {************************************************************************}
+ {*                     4-bit planar VGA mode routines                   *}
+ {************************************************************************}
+
+
+const
+
+  VideoOfs = 0;
+
+
+var
+
+  VidMem: PByteArray;
+  ScrWidth: Integer;
+
+
+procedure bytemove(var source, dest; count: Integer);
+var
+  s, d: PByte;
+begin
+  s := PByte(@source);
+  d := PByte(@dest);
+  while count > 0 do begin
+    d^ := s^;
+    Inc(d);
+    Inc(s);
+    Dec(count);
+  end;
+end;
+
+
+
+procedure PutPixel16(X,Y : Integer; Pixel: Word);
+var
+  offset: word;
+  dummy: byte;
+begin
+  Inc(x, StartXViewPort);
+  Inc(y, StartYViewPort);
+  { convert to absolute coordinates and then verify clipping...}
+  if ClipPixels then
+  begin
+    if (X < StartXViewPort) or (X > (StartXViewPort + ViewWidth)) then
+      exit;
+    if (Y < StartYViewPort) or (Y > (StartYViewPort + ViewHeight)) then
+      exit;
+  end;
+  offset := y * 80 + (x shr 3) + VideoOfs;
+  WritePortW($3ce, $0f01);       { Index 01 : Enable ops on all 4 planes }
+  WritePortW($3ce, (Pixel and $ff) shl 8); { Index 00 : Enable correct plane and write color }
+
+  WritePortW($3ce, 8 or ($8000 shr (x and $7)));{ Select correct bits to modify }
+  dummy := VidMem^[offset];     { Read data byte into VGA latch register }
+  VidMem^[offset] := dummy;     { Write the data into video memory }
+end;
+
+
+function GetPixel16(X,Y: Integer):word;
+var
+  dummy, offset: Word;
+  shift: byte;
+begin
+  Inc(x, StartXViewPort);
+  Inc(y, StartYViewPort);
+  offset := Y * 80 + (x shr 3) + VideoOfs;
+  WritePortW($3ce, 4);
+  shift := 7 - (X and 7);
+  dummy := (VidMem^[offset] shr shift) and 1;
+  WritePortB($3cf, 1);
+  dummy := dummy or (((VidMem^[offset] shr shift) and 1) shl 1);
+  WritePortB($3cf, 2);
+  dummy := dummy or (((VidMem^[offset] shr shift) and 1) shl 2);
+  WritePortB($3cf, 3);
+  dummy := dummy or (((VidMem^[offset] shr shift) and 1) shl 3);
+  GetPixel16 := dummy;
+end;
+
+
+procedure GetScanLine16(x1, x2, y: integer; var data);
+var
+  dummylong: longint;
+  Offset, count, count2, amount, index: word;
+  plane: byte;
+begin
+  inc(x1,StartXViewPort);
+  inc(x2,StartXViewPort);
+{$ifdef logging}
+  LogLn('GetScanLine16 start, length to get: '+strf(x2-x1+1)+' at y = '+strf(y));
+{$Endif logging}
+  offset := (Y + StartYViewPort) * 80 + (x1 shr 3) + VideoOfs;
+{$ifdef logging}
+  LogLn('Offset: '+HexStr(offset,4)+' - ' + strf(offset));
+{$Endif logging}
+  { first get enough pixels so offset is 32bit aligned }
+  amount := 0;
+  index := 0;
+  If ((x1 and 31) <> 0) Or
+     ((x2-x1+1) < 32) Then
+    Begin
+      If ((x2-x1+1) >= 32+32-(x1 and 31)) Then
+        amount := 32-(x1 and 31)
+      Else amount := x2-x1+1;
+{$ifdef logging}
+      LogLn('amount to align to 32bits or to get all: ' + strf(amount));
+{$Endif logging}
+      For count := 0 to amount-1 do
+        WordArray(Data)[Count] := getpixel16(x1-StartXViewPort+Count,y);
+      index := amount;
+      Inc(Offset,(amount+7) shr 3);
+{$ifdef logging}
+      LogLn('offset now: '+HexStr(offset,4)+' - ' + strf(offset));
+      LogLn('index now: '+strf(index));
+{$Endif logging}
+    End;
+  amount := x2-x1+1 - amount;
+{$ifdef logging}
+  LogLn('amount left: ' + strf(amount));
+{$Endif logging}
+  If amount = 0 Then Exit;
+  WritePortB($3ce, 4);
+  { first get everything from plane 3 (4th plane) }
+  WritePortB($3cf, 3);
+  Count := 0;
+  For Count := 1 to (amount shr 5) Do
+    Begin
+      dummylong := PLongInt(@VidMem^[offset+(Count-1)*4])^;
+      dummylong :=
+        ((dummylong and $ff) shl 24) or
+        ((dummylong and $ff00) shl 8) or
+        ((dummylong and $ff0000) shr 8) or
+        ((dummylong and $ff000000) shr 24);
+      For Count2 := 31 downto 0 Do
+        Begin
+          WordArray(Data)[index+Count2] := DummyLong and 1;
+          DummyLong := DummyLong shr 1;
+        End;
+      Inc(Index, 32);
+    End;
+{ Now get the data from the 3 other planes }
+  plane := 3;
+  Repeat
+    Dec(Index,Count*32);
+    Dec(plane);
+    WritePortB($3cf, plane);
+    Count := 0;
+    For Count := 1 to (amount shr 5) Do
+      Begin
+        dummylong := PLongInt(@VidMem^[offset+(Count-1)*4])^;
+        dummylong :=
+          ((dummylong and $ff) shl 24) or
+          ((dummylong and $ff00) shl 8) or
+          ((dummylong and $ff0000) shr 8) or
+          ((dummylong and $ff000000) shr 24);
+        For Count2 := 31 downto 0 Do
+          Begin
+            WordArray(Data)[index+Count2] :=
+              (WordArray(Data)[index+Count2] shl 1) or (DummyLong and 1);
+            DummyLong := DummyLong shr 1;
+          End;
+        Inc(Index, 32);
+      End;
+  Until plane = 0;
+  amount := amount and 31;
+  Dec(index);
+{$ifdef Logging}
+  LogLn('Last array index written to: '+strf(index));
+  LogLn('amount left: '+strf(amount)+' starting at x = '+strf(index+1));
+{$Endif logging}
+  For Count := 1 to amount Do
+    WordArray(Data)[index+Count] := getpixel16(index+Count,y);
+{$ifdef logging}
+  LogLn('First 32 bytes gotten with getscanline16: ');
+  If x2-x1+1 >= 32 Then
+    Count2 := 32
+  Else Count2 := x2-x1+1;
+  For Count := 0 to Count2-1 Do
+    Log(strf(WordArray(Data)[Count])+' ');
+  LogLn('');
+  If x2-x1+1 >= 32 Then
+    Begin
+      LogLn('Last 32 bytes gotten with getscanline16: ');
+      For Count := 31 downto 0 Do
+      Log(strf(WordArray(Data)[x2-x1-Count])+' ');
+    End;
+  LogLn('');
+  GetScanLineDefault(x1-StartXViewPort,x2-StartXViewPort,y,Data);
+  LogLn('First 32 bytes gotten with getscanlinedef: ');
+  If x2-x1+1 >= 32 Then
+    Count2 := 32
+  Else Count2 := x2-x1+1;
+  For Count := 0 to Count2-1 Do
+    Log(strf(WordArray(Data)[Count])+' ');
+  LogLn('');
+  If x2-x1+1 >= 32 Then
+    Begin
+      LogLn('Last 32 bytes gotten with getscanlinedef: ');
+      For Count := 31 downto 0 Do
+      Log(strf(WordArray(Data)[x2-x1-Count])+' ');
+    End;
+  LogLn('');
+  LogLn('GetScanLine16 end');
+{$Endif logging}
+end;
+
+
+procedure DirectPutPixel16(X,Y : Integer);
+{ x,y -> must be in global coordinates. No clipping. }
+var
+  color: word;
+  offset: word;
+  dummy: byte;
+begin
+  case CurrentWriteMode of
+    XORPut:
+      begin
+        { getpixel wants local/relative coordinates }
+        Color := GetPixel(x - StartXViewPort, y - StartYViewPort);
+        Color := CurrentColor xor Color;
+      end;
+    OrPut:
+      begin
+        { getpixel wants local/relative coordinates }
+        Color := GetPixel(x - StartXViewPort, y - StartYViewPort);
+        Color := CurrentColor or Color;
+      end;
+    AndPut:
+      begin
+        { getpixel wants local/relative coordinates }
+        Color := GetPixel(x - StartXViewPort, y - StartYViewPort);
+        Color := CurrentColor and Color;
+      end;
+    NotPut:
+      Color := Not Color;
+    else
+      Color := CurrentColor;
+  end;
+  offset := Y * 80 + (X shr 3) + VideoOfs;
+  WritePortW($3ce, $f01);
+  WritePortW($3ce, Color shl 8);
+  WritePortW($3ce, 8 or $8000 shr (X and 7));
+  dummy := VidMem^[offset];
+  VidMem^[offset] := dummy;
+end;
+
+
+procedure HLine16(x,x2,y: integer);
+var
+  xtmp: integer;
+  ScrOfs,HLength : word;
+  LMask,RMask : byte;
+begin
+  { must we swap the values? }
+  if x > x2 then
+  begin
+    xtmp := x2;
+    x2 := x;
+    x:= xtmp;
+  end;
+  { First convert to global coordinates }
+  Inc(x, StartXViewPort);
+  Inc(x2, StartXViewPort);
+  Inc(y, StartYViewPort);
+  if ClipPixels and LineClipped(x,y,x2,y,StartXViewPort,StartYViewPort,
+    StartXViewPort+ViewWidth, StartYViewPort+ViewHeight) then
+    exit;
+
+  ScrOfs := y * ScrWidth + x div 8;
+  HLength := x2 div 8 - x div 8;
+  LMask := $ff shr (x and 7);
+{$ifopt r+}
+{$define rangeOn}
+{$r-}
+{$endif}
+{$ifopt q+}
+{$define overflowOn}
+{$q-}
+{$endif}
+  RMask:=$ff shl (7 - (x2 and 7));
+{$ifdef rangeOn}
+{$undef rangeOn}
+{$r+}
+{$endif}
+{$ifdef overflowOn}
+{$undef overflowOn}
+{$q+}
+{$endif}
+  if HLength=0 then
+    LMask:=LMask and RMask;
+  WritePortB($3ce, 0);
+  if CurrentWriteMode <> NotPut Then
+    WritePortB($3cf, CurrentColor)
+  else
+    WritePortB($3cf, not CurrentColor);
+  WritePortW($3ce, $0f01);
+  WritePortB($3ce, 3);
+  case CurrentWriteMode of
+    XORPut:
+      WritePortB($3cf, 3 shl 3);
+    ANDPut:
+      WritePortB($3cf, 1 shl 3);
+    ORPut:
+      WritePortB($3cf, 2 shl 3);
+    NormalPut, NotPut:
+      WritePortB($3cf, 0)
+    else
+      WritePortB($3cf, 0)
+  end;
+
+  WritePortB($3ce, 8);
+  WritePortB($3cf, LMask);
+{$ifopt r+}
+{$define rangeOn}
+{$r-}
+{$endif}
+{$ifopt q+}
+{$define overflowOn}
+{$q-}
+{$endif}
+  VidMem^[ScrOfs] := VidMem^[ScrOfs] + 1;
+{$ifdef rangeOn}
+{$undef rangeOn}
+{$r+}
+{$endif}
+{$ifdef overflowOn}
+{$undef overflowOn}
+{$q+}
+{$endif}
+  if HLength>0 then
+  begin
+    Dec(HLength);
+    Inc(ScrOfs);
+    if HLength>0 then
+    begin
+      WritePortW($3ce, $ff08);
+      bytemove(VidMem^[ScrOfs], VidMem^[ScrOfs], HLength);
+      Inc(ScrOfs, HLength);
+    end else
+      WritePortB($3ce, 8);
+    WritePortB($3cf, RMask);
+{$ifopt r+}
+{$define rangeOn}
+{$r-}
+{$endif}
+{$ifopt q+}
+{$define overflowOn}
+{$q-}
+{$endif}
+    VidMem^[ScrOfs] := VidMem^[ScrOfs] + 1;
+{$ifdef rangeOn}
+{$undef rangeOn}
+{$r+}
+{$endif}
+{$ifdef overflowOn}
+{$undef overflowOn}
+{$q+}
+{$endif}
+  end;
+end;
+
+
+
+procedure VLine16(x,y,y2: integer);
+var
+  ytmp: integer;
+  ScrOfs,i: longint;
+  BitMask: byte;
+
+begin
+  { must we swap the values? }
+  if y > y2 then
+  begin
+    ytmp := y2;
+    y2 := y;
+    y:= ytmp;
+  end;
+  { First convert to global coordinates }
+  Inc(x, StartXViewPort);
+  Inc(y, StartYViewPort);
+  Inc(y2, StartYViewPort);
+  if ClipPixels and LineClipped(x,y,x,y2,StartXViewPort,StartYViewPort,
+    StartXViewPort+ViewWidth, StartYViewPort+ViewHeight) then
+    exit;
+  ScrOfs:=y*ScrWidth+x div 8;
+  BitMask:=$80 shr (x and 7);
+  WritePortB($3ce, 0);
+  if CurrentWriteMode <> NotPut then
+    WritePortB($3cf, CurrentColor)
+  else
+    WritePortB($3cf, not CurrentColor);
+  WritePortW($3ce, $0f01);
+  WritePortB($3ce, 8);
+  WritePortB($3cf, BitMask);
+  WritePortB($3ce, 3);
+  case CurrentWriteMode of
+    XORPut:
+      WritePortB($3cf, 3 shl 3);
+    ANDPut:
+      WritePortB($3cf, 1 shl 3);
+    ORPut:
+      WritePortB($3cf, 2 shl 3);
+    NormalPut, NotPut:
+      WritePortB($3cf, 0)
+    else
+      WritePortB($3cf, 0)
+  end;
+  for i:=y to y2 do
+  begin
+{$ifopt r+}
+{$define rangeOn}
+{$r-}
+{$endif}
+{$ifopt q+}
+{$define overflowOn}
+{$q-}
+{$endif}
+    VidMem^[ScrOfs]:=VidMem^[ScrOfs]+1;
+{$ifdef rangeOn}
+{$undef rangeOn}
+{$r+}
+{$endif}
+{$ifdef overflowOn}
+{$undef overflowOn}
+{$q+}
+{$endif}
+    Inc(ScrOfs, ScrWidth);
+  end;
+end;