Browse Source

+ VESA banked 32k/64k colour mode fast line drawing for msdos as well

git-svn-id: trunk@30249 -
nickysn 10 years ago
parent
commit
be2937bb17
2 changed files with 318 additions and 0 deletions
  1. 1 0
      packages/graph/src/msdos/graph.pp
  2. 317 0
      packages/graph/src/msdos/vesa.inc

+ 1 - 0
packages/graph/src/msdos/graph.pp

@@ -3230,6 +3230,7 @@ const CrtAddress: word = 0;
       mode.GetRGBPalette := {$ifdef fpc}@{$endif}GetVESARGBPalette;
       mode.SetVisualPage := {$ifdef fpc}@{$endif}SetVisualVESA;
       mode.SetActivePage := {$ifdef fpc}@{$endif}SetActiveVESA;
+      mode.HLine := {$ifdef fpc}@{$endif}HLineVESA32kOr64k;
     end;
 
     procedure FillCommonVESA32k(var mode: TModeInfo);

+ 317 - 0
packages/graph/src/msdos/vesa.inc

@@ -1071,6 +1071,323 @@ end;
      End;
   end;
 
+  procedure HLineVESA32kOr64k(x,x2,y: smallint); {$ifndef fpc}far;{$endif fpc}
+
+   var Offs: Longint;
+       mask, l, bankrest: longint;
+       curbank, hlength: smallint;
+   Begin
+    { must we swap the values? }
+    if x > x2 then
+      Begin
+        x := x xor x2;
+        x2 := x xor x2;
+        x:= x xor x2;
+      end;
+    { First convert to global coordinates }
+    X   := X + StartXViewPort;
+    X2  := X2 + StartXViewPort;
+    Y   := Y + StartYViewPort;
+    if ClipPixels then
+      Begin
+         if LineClipped(x,y,x2,y,StartXViewPort,StartYViewPort,
+                StartXViewPort+ViewWidth, StartYViewPort+ViewHeight) then
+            exit;
+      end;
+    {$ifdef logging2}
+    LogLn('hline '+strf(x)+' - '+strf(x2)+' on '+strf(y)+' in mode '+strf(currentwritemode));
+    {$endif logging2}
+    HLength := x2 - x + 1;
+    {$ifdef logging2}
+    LogLn('length: '+strf(hlength));
+    {$endif logging2}
+    if HLength>0 then
+      begin
+         Offs:=(Longint(y)+YOffset)*bytesperline+2*x;
+         {$ifdef logging2}
+         LogLn('Offs: '+strf(offs)+' -- '+hexstr(offs,8));
+         {$endif logging2}
+         Mask := longint(word(CurrentColor))+(longint(word(CurrentColor)) shl 16);
+         Case CurrentWriteMode of
+           AndPut:
+             Begin
+               Repeat
+                 curbank := smallint(offs shr 16);
+                 SetWriteBank(curbank);
+                 SetReadBank(curbank);
+                 {$ifdef logging2}
+                 LogLn('set bank '+strf(curbank)+' for offset '+hexstr(offs,8));
+                 {$endif logging2}
+                 If ((HLength >= 2) and
+                     ((offs and 3) = 0)) or
+                    (HLength >= 3) Then
+                 { align target }
+                   Begin
+                     If (offs and 3) <> 0 then
+                     { this cannot go past a window boundary because the }
+                     { size of a window is always a multiple of 4        }
+                       Begin
+                         {$ifdef logging2}
+                         LogLn('Aligning by drawing 1 pixel');
+                         {$endif logging2}
+                         MemW[WinWriteSeg:word(offs)] :=
+                           MemW[WinReadSeg:word(offs)] And Word(CurrentColor);
+                         Dec(HLength);
+                         inc(offs, 2);
+                       End;
+                     {$ifdef logging2}
+                     LogLn('Offset is now '+hexstr(offs,8)+', length left: '+strf(hlength));
+                     {$endif logging}
+                     { offs is now 4-bytes aligned }
+                     If HLength <= (($10000-(Offs and $ffff)) shr 1) Then
+                        bankrest := HLength
+                     else {the rest won't fit anymore in the current window }
+                       bankrest := ($10000 - (Offs and $ffff)) shr 1;
+                     { it is possible that by aligningm we ended up in a new }
+                     { bank, so set the correct bank again to make sure      }
+                     setwritebank(offs shr 16);
+                     setreadbank(offs shr 16);
+                     {$ifdef logging2}
+                     LogLn('Rest to be drawn in this window: '+strf(bankrest));
+                     {$endif logging}
+                     For l := 0 to (Bankrest div 2)-1 Do
+                       MemL[WinWriteSeg:word(offs)+l*4] :=
+                         MemL[WinReadSeg:word(offs)+l*4] And Mask;
+                     inc(offs,l*4+4);
+                     dec(hlength,l*2+2);
+                     {$ifdef logging2}
+                     LogLn('Offset is now '+hexstr(offs,8)+', length left: '+strf(hlength));
+                     {$endif logging}
+                   End
+                 Else
+                   Begin
+                     {$ifdef logging2}
+                     LogLn('Drawing leftover: '+strf(HLength)+' at offset '+hexstr(offs,8));
+                     {$endif logging}
+                     if HLength > 0 then
+                       begin
+                         { this may cross a bank at any time, so adjust          }
+                         { because this loop always runs for very little pixels, }
+                         { there's little gained by splitting it up              }
+                         setreadbank(offs shr 16);
+                         setwritebank(offs shr 16);
+                         MemW[WinWriteSeg:word(offs)] :=
+                           MemW[WinReadSeg:word(offs)] And Word(currentColor);
+                         HLength := 0
+                       end;
+                   End
+               Until HLength = 0;
+             End;
+           XorPut:
+             Begin
+               Repeat
+                 curbank := smallint(offs shr 16);
+                 SetWriteBank(curbank);
+                 SetReadBank(curbank);
+                 {$ifdef logging2}
+                 LogLn('set bank '+strf(curbank)+' for offset '+hexstr(offs,8));
+                 {$endif logging2}
+                 If ((HLength >= 2) and
+                     ((offs and 3) = 0)) or
+                    (HLength >= 3) Then
+                 { align target }
+                   Begin
+                     If (offs and 3) <> 0 then
+                     { this cannot go past a window boundary because the }
+                     { size of a window is always a multiple of 4        }
+                       Begin
+                         {$ifdef logging2}
+                         LogLn('Aligning by drawing 1 pixel');
+                         {$endif logging2}
+                         MemW[WinWriteSeg:word(offs)] :=
+                           MemW[WinReadSeg:word(offs)] Xor Word(CurrentColor);
+                         Dec(HLength);
+                         inc(offs, 2);
+                       End;
+                     {$ifdef logging2}
+                     LogLn('Offset is now '+hexstr(offs,8)+', length left: '+strf(hlength));
+                     {$endif logging}
+                     { offs is now 4-bytes aligned }
+                     If HLength <= (($10000-(Offs and $ffff)) shr 1) Then
+                        bankrest := HLength
+                     else {the rest won't fit anymore in the current window }
+                       bankrest := ($10000 - (Offs and $ffff)) shr 1;
+                     { it is possible that by aligningm we ended up in a new }
+                     { bank, so set the correct bank again to make sure      }
+                     setwritebank(offs shr 16);
+                     setreadbank(offs shr 16);
+                     {$ifdef logging2}
+                     LogLn('Rest to be drawn in this window: '+strf(bankrest));
+                     {$endif logging}
+                     For l := 0 to (Bankrest div 2)-1 Do
+                       MemL[WinWriteSeg:word(offs)+l*4] :=
+                         MemL[WinReadSeg:word(offs)+l*4] Xor Mask;
+                     inc(offs,l*4+4);
+                     dec(hlength,l*2+2);
+                     {$ifdef logging2}
+                     LogLn('Offset is now '+hexstr(offs,8)+', length left: '+strf(hlength));
+                     {$endif logging}
+                   End
+                 Else
+                   Begin
+                     {$ifdef logging2}
+                     LogLn('Drawing leftover: '+strf(HLength)+' at offset '+hexstr(offs,8));
+                     {$endif logging}
+                     if HLength > 0 then
+                       begin
+                         { this may cross a bank at any time, so adjust          }
+                         { because this loop always runs for very little pixels, }
+                         { there's little gained by splitting it up              }
+                         setreadbank(offs shr 16);
+                         setwritebank(offs shr 16);
+                         MemW[WinWriteSeg:word(offs)] :=
+                           MemW[WinReadSeg:word(offs)] Xor Word(currentColor);
+                         HLength := 0
+                       end;
+                   End
+               Until HLength = 0;
+             End;
+           OrPut:
+             Begin
+               Repeat
+                 curbank := smallint(offs shr 16);
+                 SetWriteBank(curbank);
+                 SetReadBank(curbank);
+                 {$ifdef logging2}
+                 LogLn('set bank '+strf(curbank)+' for offset '+hexstr(offs,8));
+                 {$endif logging2}
+                 If ((HLength >= 2) and
+                     ((offs and 3) = 0)) or
+                    (HLength >= 3) Then
+                 { align target }
+                   Begin
+                     If (offs and 3) <> 0 then
+                     { this cannot go past a window boundary because the }
+                     { size of a window is always a multiple of 4        }
+                       Begin
+                         {$ifdef logging2}
+                         LogLn('Aligning by drawing 1 pixel');
+                         {$endif logging2}
+                         MemW[WinWriteSeg:word(offs)] :=
+                           MemW[WinReadSeg:word(offs)] Or Word(CurrentColor);
+                         Dec(HLength);
+                         inc(offs, 2);
+                       End;
+                     {$ifdef logging2}
+                     LogLn('Offset is now '+hexstr(offs,8)+', length left: '+strf(hlength));
+                     {$endif logging}
+                     { offs is now 4-bytes aligned }
+                     If HLength <= (($10000-(Offs and $ffff)) shr 1) Then
+                        bankrest := HLength
+                     else {the rest won't fit anymore in the current window }
+                       bankrest := ($10000 - (Offs and $ffff)) shr 1;
+                     { it is possible that by aligningm we ended up in a new }
+                     { bank, so set the correct bank again to make sure      }
+                     setwritebank(offs shr 16);
+                     setreadbank(offs shr 16);
+                     {$ifdef logging2}
+                     LogLn('Rest to be drawn in this window: '+strf(bankrest));
+                     {$endif logging}
+                     For l := 0 to (Bankrest div 2)-1 Do
+                       MemL[WinWriteSeg:word(offs)+l*4] :=
+                         MemL[WinReadSeg:word(offs)+l*4] Or Mask;
+                     inc(offs,l*4+4);
+                     dec(hlength,l*2+2);
+                     {$ifdef logging2}
+                     LogLn('Offset is now '+hexstr(offs,8)+', length left: '+strf(hlength));
+                     {$endif logging}
+                   End
+                 Else
+                   Begin
+                     {$ifdef logging2}
+                     LogLn('Drawing leftover: '+strf(HLength)+' at offset '+hexstr(offs,8));
+                     {$endif logging}
+                     if HLength > 0 then
+                       begin
+                         { this may cross a bank at any time, so adjust          }
+                         { because this loop always runs for very little pixels, }
+                         { there's little gained by splitting it up              }
+                         setreadbank(offs shr 16);
+                         setwritebank(offs shr 16);
+                         MemW[WinWriteSeg:word(offs)] :=
+                           MemW[WinReadSeg:word(offs)] Or Word(currentColor);
+                         HLength := 0
+                       end;
+                   End
+               Until HLength = 0;
+             End
+           Else
+             Begin
+               If CurrentWriteMode = NotPut Then
+                 Mask := Not(Mask);
+               Repeat
+                 curbank := smallint(offs shr 16);
+                 SetWriteBank(curbank);
+                 SetReadBank(curbank);
+                 {$ifdef logging2}
+                 LogLn('set bank '+strf(curbank)+' for offset '+hexstr(offs,8));
+                 {$endif logging2}
+                 If ((HLength >= 2) and
+                     ((offs and 3) = 0)) or
+                    (HLength >= 3) Then
+                 { align target }
+                   Begin
+                     If (offs and 3) <> 0 then
+                     { this cannot go past a window boundary because the }
+                     { size of a window is always a multiple of 4        }
+                       Begin
+                         {$ifdef logging2}
+                         LogLn('Aligning by drawing 1 pixel');
+                         {$endif logging2}
+                         MemW[WinWriteSeg:word(offs)] := Word(Mask);
+                         Dec(HLength);
+                         inc(offs, 2);
+                       End;
+                     {$ifdef logging2}
+                     LogLn('Offset is now '+hexstr(offs,8)+', length left: '+strf(hlength));
+                     {$endif logging}
+                     { offs is now 4-bytes aligned }
+                     If HLength <= (($10000-(Offs and $ffff)) shr 1) Then
+                        bankrest := HLength
+                     else {the rest won't fit anymore in the current window }
+                       bankrest := ($10000 - (Offs and $ffff)) shr 1;
+                     { it is possible that by aligningm we ended up in a new }
+                     { bank, so set the correct bank again to make sure      }
+                     setwritebank(offs shr 16);
+                     setreadbank(offs shr 16);
+                     {$ifdef logging2}
+                     LogLn('Rest to be drawn in this window: '+strf(bankrest));
+                     {$endif logging}
+                     For l := 0 to (Bankrest div 2)-1 Do
+                       MemL[WinWriteSeg:word(offs)+l*4] := Mask;
+                     inc(offs,l*4+4);
+                     dec(hlength,l*2+2);
+                     {$ifdef logging2}
+                     LogLn('Offset is now '+hexstr(offs,8)+', length left: '+strf(hlength));
+                     {$endif logging}
+                   End
+                 Else
+                   Begin
+                     {$ifdef logging2}
+                     LogLn('Drawing leftover: '+strf(HLength)+' at offset '+hexstr(offs,8));
+                     {$endif logging}
+                     if HLength > 0 then
+                       begin
+                         { this may cross a bank at any time, so adjust          }
+                         { because this loop always runs for very little pixels, }
+                         { there's little gained by splitting it up              }
+                         setreadbank(offs shr 16);
+                         setwritebank(offs shr 16);
+                         MemW[WinWriteSeg:word(offs)] := Word(Mask);
+                         HLength := 0
+                       end;
+                   End
+               Until HLength = 0;
+             End;
+         End;
+       end;
+   end;
+
 
  {************************************************************************}
  {*                     4-bit pixels VESA mode routines                  *}