You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1705 lines
44 KiB
Plaintext
1705 lines
44 KiB
Plaintext
unit GR32_Filters;
|
|
|
|
(* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1 or LGPL 2.1 with linking exception
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of the
|
|
* Free Pascal modified version of the GNU Lesser General Public License
|
|
* Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
|
|
* of this license are applicable instead of those above.
|
|
* Please see the file LICENSE.txt for additional information concerning this
|
|
* license.
|
|
*
|
|
* The Original Code is Graphics32
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Alex A. Denisov
|
|
*
|
|
* Portions created by the Initial Developer are Copyright (C) 2000-2009
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Michael Hansen |
|
* - 2007/02/25 - Logical Mask Operations and related types
|
|
* - 2007/02/27 - CopyComponents
|
|
* - 2007/05/10 - Logical Mask Operation functions in pascal versions
|
|
*
|
|
* ***** END LICENSE BLOCK ***** *)
|
|
|
|
interface
|
|
|
|
{$I GR32.inc}
|
|
|
|
{$IFDEF TARGET_X64}
|
|
{$DEFINE PUREPASCAL}
|
|
{$ENDIF}
|
|
|
|
uses
|
|
{$IFDEF FPC}
|
|
{$ELSE}
|
|
Windows,
|
|
{$ENDIF}
|
|
Classes, SysUtils, GR32, GR32_Blend, GR32_System, GR32_Bindings;
|
|
|
|
{ Basic processing }
|
|
type
|
|
TLUT8 = array [Byte] of Byte;
|
|
TLogicalOperator = (loXOR, loAND, loOR);
|
|
|
|
procedure CopyComponents(Dst, Src: TCustomBitmap32; Components: TColor32Components);overload;
|
|
procedure CopyComponents(Dst: TCustomBitmap32; DstX, DstY: Integer; Src: TCustomBitmap32;
|
|
SrcRect: TRect; Components: TColor32Components); overload;
|
|
|
|
procedure AlphaToGrayscale(Dst, Src: TCustomBitmap32);
|
|
procedure ColorToGrayscale(Dst, Src: TCustomBitmap32; PreserveAlpha: Boolean = False);
|
|
procedure IntensityToAlpha(Dst, Src: TCustomBitmap32);
|
|
|
|
procedure Invert(Dst, Src: TCustomBitmap32; Components : TColor32Components = [ccAlpha, ccRed, ccGreen, ccBlue]);
|
|
procedure InvertRGB(Dst, Src: TCustomBitmap32);
|
|
|
|
procedure ApplyLUT(Dst, Src: TCustomBitmap32; const LUT: TLUT8; PreserveAlpha: Boolean = False);
|
|
procedure ChromaKey(ABitmap: TCustomBitmap32; TrColor: TColor32);
|
|
|
|
function CreateBitmask(Components: TColor32Components): TColor32;
|
|
|
|
procedure ApplyBitmask(Dst: TCustomBitmap32; DstX, DstY: Integer; Src: TCustomBitmap32;
|
|
SrcRect: TRect; Bitmask: TColor32; LogicalOperator: TLogicalOperator); overload;
|
|
procedure ApplyBitmask(ABitmap: TCustomBitmap32; ARect: TRect; Bitmask: TColor32;
|
|
LogicalOperator: TLogicalOperator); overload;
|
|
|
|
procedure CheckParams(Dst, Src: TCustomBitmap32; ResizeDst: Boolean = True);
|
|
|
|
implementation
|
|
|
|
uses
|
|
GR32_Lowlevel;
|
|
|
|
const
|
|
SEmptyBitmap = 'The bitmap is nil';
|
|
SEmptySource = 'The source is nil';
|
|
SEmptyDestination = 'Destination is nil';
|
|
SNoInPlace = 'In-place operation is not supported here';
|
|
|
|
type
|
|
{ Function Prototypes }
|
|
TLogicalMaskLine = procedure(Dst: PColor32; Mask: TColor32; Count: Integer); //Inplace
|
|
TLogicalMaskLineEx = procedure(Src, Dst: PColor32; Count: Integer; Mask: TColor32); //"Src To Dst"
|
|
|
|
{$HINTS OFF}
|
|
var
|
|
{ masked logical operation functions }
|
|
LogicalMaskLineXor: TLogicalMaskLine;
|
|
LogicalMaskLineOr: TLogicalMaskLine;
|
|
LogicalMaskLineAnd: TLogicalMaskLine;
|
|
|
|
LogicalMaskLineXorEx: TLogicalMaskLineEx;
|
|
LogicalMaskLineOrEx: TLogicalMaskLineEx;
|
|
LogicalMaskLineAndEx: TLogicalMaskLineEx;
|
|
{$HINTS ON}
|
|
|
|
{ Access to masked logical operation functions corresponding to a logical operation mode }
|
|
const
|
|
LOGICAL_MASK_LINE: array[TLogicalOperator] of ^TLogicalMaskLine = (
|
|
(@@LogicalMaskLineXor),
|
|
(@@LogicalMaskLineAnd),
|
|
(@@LogicalMaskLineOr)
|
|
);
|
|
|
|
LOGICAL_MASK_LINE_EX: array[TLogicalOperator] of ^TLogicalMaskLineEx = (
|
|
(@@LogicalMaskLineXorEx),
|
|
(@@LogicalMaskLineAndEx),
|
|
(@@LogicalMaskLineOrEx)
|
|
);
|
|
|
|
procedure CheckParams(Dst, Src: TCustomBitmap32; ResizeDst: Boolean = True);
|
|
begin
|
|
if not Assigned(Src) then
|
|
raise Exception.Create(SEmptySource);
|
|
|
|
if not Assigned(Dst) then
|
|
raise Exception.Create(SEmptyDestination);
|
|
|
|
if ResizeDst then Dst.SetSize(Src.Width, Src.Height);
|
|
end;
|
|
|
|
procedure CopyComponents(Dst, Src: TCustomBitmap32; Components: TColor32Components);
|
|
begin
|
|
if Components = [] then Exit;
|
|
CheckParams(Dst, Src);
|
|
CopyComponents(Dst, 0, 0, Src, Src.BoundsRect, Components);
|
|
end;
|
|
|
|
procedure CopyComponents(Dst: TCustomBitmap32; DstX, DstY: Integer; Src: TCustomBitmap32;
|
|
SrcRect: TRect; Components: TColor32Components);
|
|
var
|
|
I, J, Count, ComponentCount, XOffset: Integer;
|
|
Mask: TColor32;
|
|
SrcRow, DstRow: PColor32Array;
|
|
PBDst, PBSrc: PByteArray;
|
|
DstRect: TRect;
|
|
begin
|
|
if Components = [] then Exit;
|
|
CheckParams(Dst, Src, False);
|
|
|
|
ComponentCount := 0;
|
|
XOffset := 0;
|
|
Mask := 0;
|
|
if ccAlpha in Components then
|
|
begin
|
|
Inc(ComponentCount);
|
|
Inc(Mask, $FF000000);
|
|
XOffset := 3;
|
|
end;
|
|
if ccRed in Components then
|
|
begin
|
|
Inc(ComponentCount);
|
|
Inc(Mask, $00FF0000);
|
|
XOffset := 2;
|
|
end;
|
|
if ccGreen in Components then
|
|
begin
|
|
Inc(ComponentCount);
|
|
Inc(Mask, $0000FF00);
|
|
XOffset := 1;
|
|
end;
|
|
if ccBlue in Components then
|
|
begin
|
|
Inc(ComponentCount);
|
|
Inc(Mask, $000000FF);
|
|
end;
|
|
|
|
with Dst do
|
|
begin
|
|
IntersectRect(SrcRect, SrcRect, Src.BoundsRect);
|
|
if (SrcRect.Right < SrcRect.Left) or (SrcRect.Bottom < SrcRect.Top) then Exit;
|
|
|
|
DstX := Clamp(DstX, 0, Width);
|
|
DstY := Clamp(DstY, 0, Height);
|
|
|
|
DstRect.TopLeft := Point(DstX, DstY);
|
|
DstRect.Right := DstX + SrcRect.Right - SrcRect.Left;
|
|
DstRect.Bottom := DstY + SrcRect.Bottom - SrcRect.Top;
|
|
|
|
IntersectRect(DstRect, DstRect, BoundsRect);
|
|
IntersectRect(DstRect, DstRect, ClipRect);
|
|
if (DstRect.Right < DstRect.Left) or (DstRect.Bottom < DstRect.Top) then Exit;
|
|
|
|
if not MeasuringMode then
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
with DstRect do
|
|
if (Bottom - Top) > 0 then
|
|
begin
|
|
SrcRow := Pointer(Src.PixelPtr[SrcRect.Left, SrcRect.Top]);
|
|
DstRow := Pointer(PixelPtr[Left, Top]);
|
|
Count := Right - Left;
|
|
if Count > 16 then
|
|
case ComponentCount of
|
|
1://Byte ptr approach
|
|
begin
|
|
PBSrc := Pointer(SrcRow);
|
|
Inc(PBSrc, XOffset); // shift the pointer to the given component of the first pixel
|
|
PBDst := Pointer(DstRow);
|
|
Inc(PBDst, XOffset);
|
|
|
|
Count := Count * 4 - 64;
|
|
Inc(PBSrc, Count);
|
|
Inc(PBDst, Count);
|
|
|
|
for I := 0 to Bottom - Top - 1 do
|
|
begin
|
|
//16x enrolled loop
|
|
J := - Count;
|
|
repeat
|
|
PBDst[J] := PBSrc[J];
|
|
PBDst[J + 4] := PBSrc[J + 4];
|
|
PBDst[J + 8] := PBSrc[J + 8];
|
|
PBDst[J + 12] := PBSrc[J + 12];
|
|
PBDst[J + 16] := PBSrc[J + 16];
|
|
PBDst[J + 20] := PBSrc[J + 20];
|
|
PBDst[J + 24] := PBSrc[J + 24];
|
|
PBDst[J + 28] := PBSrc[J + 28];
|
|
PBDst[J + 32] := PBSrc[J + 32];
|
|
PBDst[J + 36] := PBSrc[J + 36];
|
|
PBDst[J + 40] := PBSrc[J + 40];
|
|
PBDst[J + 44] := PBSrc[J + 44];
|
|
PBDst[J + 48] := PBSrc[J + 48];
|
|
PBDst[J + 52] := PBSrc[J + 52];
|
|
PBDst[J + 56] := PBSrc[J + 56];
|
|
PBDst[J + 60] := PBSrc[J + 60];
|
|
Inc(J, 64)
|
|
until J > 0;
|
|
|
|
//The rest
|
|
Dec(J, 64);
|
|
while J < 0 do
|
|
begin
|
|
PBDst[J + 64] := PBSrc[J + 64];
|
|
Inc(J, 4);
|
|
end;
|
|
Inc(PBSrc, Src.Width * 4);
|
|
Inc(PBDst, Width * 4);
|
|
end;
|
|
end;
|
|
2, 3: //Masked approach
|
|
begin
|
|
Count := Count - 8;
|
|
Inc(DstRow, Count);
|
|
Inc(SrcRow, Count);
|
|
for I := 0 to Bottom - Top - 1 do
|
|
begin
|
|
//8x enrolled loop
|
|
J := - Count;
|
|
repeat
|
|
Mask := not Mask;
|
|
DstRow[J] := DstRow[J] and Mask;
|
|
DstRow[J + 1] := DstRow[J + 1] and Mask;
|
|
DstRow[J + 2] := DstRow[J + 2] and Mask;
|
|
DstRow[J + 3] := DstRow[J + 3] and Mask;
|
|
DstRow[J + 4] := DstRow[J + 4] and Mask;
|
|
DstRow[J + 5] := DstRow[J + 5] and Mask;
|
|
DstRow[J + 6] := DstRow[J + 6] and Mask;
|
|
DstRow[J + 7] := DstRow[J + 7] and Mask;
|
|
|
|
Mask := not Mask;
|
|
DstRow[J] := DstRow[J] or SrcRow[J] and Mask;
|
|
DstRow[J + 1] := DstRow[J + 1] or SrcRow[J + 1] and Mask;
|
|
DstRow[J + 2] := DstRow[J + 2] or SrcRow[J + 2] and Mask;
|
|
DstRow[J + 3] := DstRow[J + 3] or SrcRow[J + 3] and Mask;
|
|
DstRow[J + 4] := DstRow[J + 4] or SrcRow[J + 4] and Mask;
|
|
DstRow[J + 5] := DstRow[J + 5] or SrcRow[J + 5] and Mask;
|
|
DstRow[J + 6] := DstRow[J + 6] or SrcRow[J + 6] and Mask;
|
|
DstRow[J + 7] := DstRow[J + 7] or SrcRow[J + 7] and Mask;
|
|
|
|
Inc(J, 8);
|
|
until J > 0;
|
|
|
|
//The rest
|
|
Dec(J, 8);
|
|
while J < 0 do
|
|
begin
|
|
DstRow[J + 8] := DstRow[J + 8] and not Mask or SrcRow[J + 8] and Mask;
|
|
Inc(J);
|
|
end;
|
|
Inc(SrcRow, Src.Width);
|
|
Inc(DstRow, Width);
|
|
end;
|
|
end;
|
|
4: //full copy approach approach, use MoveLongWord
|
|
for I := 0 to Bottom - Top - 1 do
|
|
begin
|
|
MoveLongWord(SrcRow^, DstRow^, Count);
|
|
Inc(SrcRow, Src.Width);
|
|
Inc(DstRow, Width);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
for I := 0 to Bottom - Top - 1 do
|
|
begin
|
|
for J := 0 to Count - 1 do
|
|
DstRow[J] := DstRow[J] and not Mask or SrcRow[J] and Mask;
|
|
Inc(SrcRow, Src.Width);
|
|
Inc(DstRow, Width);
|
|
end;
|
|
end;
|
|
end;
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
Changed(DstRect);
|
|
end;
|
|
end;
|
|
|
|
procedure AlphaToGrayscale(Dst, Src: TCustomBitmap32);
|
|
var
|
|
I: Integer;
|
|
D, S : PColor32EntryArray;
|
|
Alpha: Byte;
|
|
begin
|
|
CheckParams(Dst, Src);
|
|
S := PColor32EntryArray(@Src.Bits[0]);
|
|
D := PColor32EntryArray(@Dst.Bits[0]);
|
|
for I := 0 to Src.Height * Src.Width -1 do
|
|
begin
|
|
Alpha := S[I].A;
|
|
with D[I] do
|
|
begin
|
|
R := Alpha;
|
|
G := Alpha;
|
|
B := Alpha;
|
|
end;
|
|
end;
|
|
Dst.Changed;
|
|
end;
|
|
|
|
procedure IntensityToAlpha(Dst, Src: TCustomBitmap32);
|
|
var
|
|
I: Integer;
|
|
D, S : PColor32EntryArray;
|
|
begin
|
|
CheckParams(Dst, Src);
|
|
S := PColor32EntryArray(@Src.Bits[0]);
|
|
D := PColor32EntryArray(@Dst.Bits[0]);
|
|
for I := 0 to Src.Width * Src.Height - 1 do
|
|
D[I].A := (S[I].R * 61 + S[I].G * 174 + S[I].B * 21) shr 8;
|
|
Dst.Changed;
|
|
end;
|
|
|
|
procedure Invert(Dst, Src: TCustomBitmap32; Components : TColor32Components = [ccAlpha, ccRed, ccGreen, ccBlue]);
|
|
var
|
|
Mask: TColor32;
|
|
begin
|
|
if Components = [] then Exit;
|
|
Mask := CreateBitmask(Components);
|
|
if Src = Dst then
|
|
begin
|
|
//Inplace
|
|
CheckParams(Dst, Src, False);
|
|
ApplyBitmask(Src, Src.BoundsRect, Mask, loXOR);
|
|
end
|
|
else
|
|
begin
|
|
//Src -> Dst
|
|
CheckParams(Dst, Src);
|
|
ApplyBitmask(Dst, 0, 0, Src, Src.BoundsRect, Mask, loXOR);
|
|
end;
|
|
end;
|
|
|
|
procedure InvertRGB(Dst, Src: TCustomBitmap32);
|
|
begin
|
|
Invert(Src, Dst, [ccRed, ccGreen, ccBlue]);
|
|
end;
|
|
|
|
procedure ColorToGrayscale(Dst, Src: TCustomBitmap32; PreserveAlpha: Boolean = False);
|
|
var
|
|
I: Integer;
|
|
D, S: PColor32;
|
|
begin
|
|
CheckParams(Dst, Src);
|
|
D := @Dst.Bits[0];
|
|
S := @Src.Bits[0];
|
|
|
|
if PreserveAlpha then
|
|
for I := 0 to Src.Width * Src.Height - 1 do
|
|
begin
|
|
D^ := Gray32(Intensity(S^), AlphaComponent(S^));
|
|
Inc(S); Inc(D);
|
|
end
|
|
else
|
|
for I := 0 to Src.Width * Src.Height - 1 do
|
|
begin
|
|
D^ := Gray32(Intensity(S^));
|
|
Inc(S); Inc(D);
|
|
end;
|
|
|
|
Dst.Changed;
|
|
end;
|
|
|
|
procedure ApplyLUT(Dst, Src: TCustomBitmap32; const LUT: TLUT8; PreserveAlpha: Boolean = False);
|
|
var
|
|
I: Integer;
|
|
D, S: PColor32Entry;
|
|
begin
|
|
CheckParams(Dst, Src);
|
|
D := @Dst.Bits[0];
|
|
S := @Src.Bits[0];
|
|
|
|
if PreserveAlpha then
|
|
for I := 0 to Src.Width * Src.Height - 1 do
|
|
begin
|
|
D.ARGB := D.ARGB and $FF000000 + LUT[S.B] + LUT[S.G] shl 8 + LUT[S.R] shl 16;
|
|
Inc(S);
|
|
Inc(D);
|
|
end
|
|
else
|
|
for I := 0 to Src.Width * Src.Height - 1 do
|
|
begin
|
|
D.ARGB := $FF000000 + LUT[S.B] + LUT[S.G] shl 8 + LUT[S.R] shl 16;
|
|
Inc(S);
|
|
Inc(D);
|
|
end;
|
|
|
|
Dst.Changed;
|
|
end;
|
|
|
|
procedure ChromaKey(ABitmap: TCustomBitmap32; TrColor: TColor32);
|
|
var
|
|
P: PColor32;
|
|
C: TColor32;
|
|
I: Integer;
|
|
begin
|
|
TrColor := TrColor and $00FFFFFF;
|
|
with ABitmap do
|
|
begin
|
|
P := PixelPtr[0, 0];
|
|
for I := 0 to Width * Height - 1 do
|
|
begin
|
|
C := P^ and $00FFFFFF;
|
|
if C = TrColor then P^ := C;
|
|
Inc(P)
|
|
end;
|
|
end;
|
|
|
|
ABitmap.Changed;
|
|
end;
|
|
|
|
function CreateBitmask(Components: TColor32Components): TColor32;
|
|
begin
|
|
Result := 0;
|
|
if ccAlpha in Components then Inc(Result, $FF000000);
|
|
if ccRed in Components then Inc(Result, $00FF0000);
|
|
if ccGreen in Components then Inc(Result, $0000FF00);
|
|
if ccBlue in Components then Inc(Result, $000000FF);
|
|
end;
|
|
|
|
procedure ApplyBitmask(Dst: TCustomBitmap32; DstX, DstY: Integer; Src: TCustomBitmap32;
|
|
SrcRect: TRect; Bitmask: TColor32; LogicalOperator: TLogicalOperator);
|
|
var
|
|
I, Count: Integer;
|
|
DstRect: TRect;
|
|
MaskProc : TLogicalMaskLineEx;
|
|
begin
|
|
CheckParams(Dst, Src, False);
|
|
|
|
MaskProc := LOGICAL_MASK_LINE_EX[LogicalOperator]^;
|
|
|
|
if Assigned(MaskProc) then
|
|
with Dst do
|
|
begin
|
|
IntersectRect(SrcRect, SrcRect, Src.BoundsRect);
|
|
if (SrcRect.Right < SrcRect.Left) or (SrcRect.Bottom < SrcRect.Top) then Exit;
|
|
|
|
DstX := Clamp(DstX, 0, Width);
|
|
DstY := Clamp(DstY, 0, Height);
|
|
|
|
DstRect.TopLeft := Point(DstX, DstY);
|
|
DstRect.Right := DstX + SrcRect.Right - SrcRect.Left;
|
|
DstRect.Bottom := DstY + SrcRect.Bottom - SrcRect.Top;
|
|
|
|
IntersectRect(DstRect, DstRect, Dst.BoundsRect);
|
|
IntersectRect(DstRect, DstRect, Dst.ClipRect);
|
|
if (DstRect.Right < DstRect.Left) or (DstRect.Bottom < DstRect.Top) then Exit;
|
|
|
|
|
|
if not MeasuringMode then
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
with DstRect do
|
|
if (Bottom - Top) > 0 then
|
|
begin
|
|
Count := Right - Left;
|
|
if Count > 0 then
|
|
for I := 0 to Bottom - Top - 1 do
|
|
MaskProc(Src.PixelPtr[SrcRect.Left, SrcRect.Top + I], PixelPtr[Left, Top + I], Count, Bitmask)
|
|
end;
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
Changed(DstRect);
|
|
end;
|
|
end;
|
|
|
|
procedure ApplyBitmask(ABitmap: TCustomBitmap32; ARect: TRect; Bitmask: TColor32;
|
|
LogicalOperator: TLogicalOperator);
|
|
var
|
|
I, Count: Integer;
|
|
MaskProc : TLogicalMaskLine;
|
|
begin
|
|
if not Assigned(ABitmap) then
|
|
raise Exception.Create(SEmptyBitmap);
|
|
|
|
MaskProc := LOGICAL_MASK_LINE[LogicalOperator]^;
|
|
|
|
if Assigned(MaskProc) then
|
|
with ABitmap do
|
|
begin
|
|
IntersectRect(ARect, ARect, BoundsRect);
|
|
IntersectRect(ARect, ARect, ClipRect);
|
|
if (ARect.Right < ARect.Left) or (ARect.Bottom < ARect.Top) then Exit;
|
|
|
|
if not MeasuringMode then
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
with ARect do
|
|
if (Bottom - Top) > 0 then
|
|
begin
|
|
Count := Right - Left;
|
|
if Count > 0 then
|
|
begin
|
|
if Count = Width then
|
|
MaskProc(PixelPtr[Left, Top], Bitmask, Count * (Bottom - Top))
|
|
else
|
|
for I := Top to Bottom - 1 do
|
|
MaskProc(PixelPtr[Left, I], Bitmask, Count);
|
|
end;
|
|
end;
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
Changed(ARect);
|
|
end;
|
|
end;
|
|
|
|
{ In-place logical mask functions }
|
|
{ Non - MMX versions}
|
|
|
|
procedure XorLine_Pas(Dst: PColor32; Mask: TColor32; Count: Integer);
|
|
var
|
|
DstRow: PColor32Array absolute Dst;
|
|
begin
|
|
Inc(Dst, Count);
|
|
Count := - Count;
|
|
repeat
|
|
DstRow[Count] := DstRow[Count] xor Mask;
|
|
Inc(Count);
|
|
until Count = 0;
|
|
end;
|
|
|
|
procedure OrLine_Pas(Dst: PColor32; Mask: TColor32; Count: Integer);
|
|
var
|
|
DstRow: PColor32Array absolute Dst;
|
|
begin
|
|
Inc(Dst, Count);
|
|
Count := - Count;
|
|
repeat
|
|
DstRow[Count] := DstRow[Count] or Mask;
|
|
Inc(Count);
|
|
until Count = 0;
|
|
end;
|
|
|
|
procedure AndLine_Pas(Dst: PColor32; Mask: TColor32; Count: Integer);
|
|
var
|
|
DstRow: PColor32Array absolute Dst;
|
|
begin
|
|
Inc(Dst, Count);
|
|
Count := - Count;
|
|
repeat
|
|
DstRow[Count] := DstRow[Count] and Mask;
|
|
Inc(Count);
|
|
until Count = 0;
|
|
end;
|
|
|
|
{$IFNDEF PUREPASCAL}
|
|
|
|
procedure XorLine_ASM(Dst: PColor32; Mask: TColor32; Count: Integer);
|
|
// No speedup achieveable using MMX
|
|
asm
|
|
{$IFDEF TARGET_x86}
|
|
TEST ECX, ECX
|
|
JZ @Exit
|
|
|
|
PUSH EBX
|
|
MOV EBX, ECX
|
|
SHR ECX, 4
|
|
SHL ECX, 4
|
|
JZ @PrepSingleLoop
|
|
LEA EAX, [EAX + ECX * 4]
|
|
SHL ECX, 2
|
|
NEG ECX
|
|
|
|
@ChunkLoop:
|
|
//16x unrolled loop
|
|
XOR [EAX + ECX], EDX
|
|
XOR [EAX + ECX + 4], EDX
|
|
XOR [EAX + ECX + 8], EDX
|
|
XOR [EAX + ECX + 12], EDX
|
|
|
|
XOR [EAX + ECX + 16], EDX
|
|
XOR [EAX + ECX + 20], EDX
|
|
XOR [EAX + ECX + 24], EDX
|
|
XOR [EAX + ECX + 28], EDX
|
|
|
|
XOR [EAX + ECX + 32], EDX
|
|
XOR [EAX + ECX + 36], EDX
|
|
XOR [EAX + ECX + 40], EDX
|
|
XOR [EAX + ECX + 44], EDX
|
|
|
|
XOR [EAX + ECX + 48], EDX
|
|
XOR [EAX + ECX + 52], EDX
|
|
XOR [EAX + ECX + 56], EDX
|
|
XOR [EAX + ECX + 60], EDX
|
|
|
|
ADD ECX, 16 * 4
|
|
JNZ @ChunkLoop
|
|
|
|
@PrepSingleLoop:
|
|
MOV ECX, EBX
|
|
SHR EBX, 4
|
|
SHL EBX, 4
|
|
SUB ECX, EBX
|
|
JZ @PopExit
|
|
|
|
LEA EAX, [EAX + ECX * 4]
|
|
NEG ECX
|
|
|
|
@SingleLoop:
|
|
XOR [EAX + ECX * 4], EDX
|
|
INC ECX
|
|
JNZ @SingleLoop
|
|
|
|
@PopExit:
|
|
POP EBX
|
|
|
|
@Exit:
|
|
{$ENDIF}
|
|
|
|
{$IFDEF TARGET_x64}
|
|
TEST R8D, R8D
|
|
JZ @Exit
|
|
|
|
MOV EAX, R8D
|
|
SHR R8D, 4
|
|
SHL R8D, 4
|
|
JZ @PrepSingleLoop
|
|
LEA RCX, [RCX + R8D * 4]
|
|
SHL R8D, 2
|
|
NEG R8D
|
|
|
|
@ChunkLoop:
|
|
//16x unrolled loop
|
|
XOR [RCX + R8D], EDX
|
|
XOR [RCX + R8D + 4], EDX
|
|
XOR [RCX + R8D + 8], EDX
|
|
XOR [RCX + R8D + 12], EDX
|
|
|
|
XOR [RCX + R8D + 16], EDX
|
|
XOR [RCX + R8D + 20], EDX
|
|
XOR [RCX + R8D + 24], EDX
|
|
XOR [RCX + R8D + 28], EDX
|
|
|
|
XOR [RCX + R8D + 32], EDX
|
|
XOR [RCX + R8D + 36], EDX
|
|
XOR [RCX + R8D + 40], EDX
|
|
XOR [RCX + R8D + 44], EDX
|
|
|
|
XOR [RCX + R8D + 48], EDX
|
|
XOR [RCX + R8D + 52], EDX
|
|
XOR [RCX + R8D + 56], EDX
|
|
XOR [RCX + R8D + 60], EDX
|
|
|
|
ADD R8D, 16 * 4
|
|
JNZ @ChunkLoop
|
|
|
|
@PrepSingleLoop:
|
|
MOV R8D, EAX
|
|
SHR EAX, 4
|
|
SHL EAX, 4
|
|
SUB R8D, EAX
|
|
JZ @Exit
|
|
|
|
LEA RCX, [RCX + R8D * 4]
|
|
NEG R8D
|
|
|
|
@SingleLoop:
|
|
XOR [RCX + R8D * 4], EDX
|
|
INC R8D
|
|
JNZ @SingleLoop
|
|
|
|
@Exit:
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure OrLine_ASM(Dst: PColor32; Mask: TColor32; Count: Integer);
|
|
// No speedup achieveable using MMX
|
|
asm
|
|
{$IFDEF TARGET_x86}
|
|
TEST ECX, ECX
|
|
JZ @Exit
|
|
|
|
PUSH EBX
|
|
MOV EBX, ECX
|
|
SHR ECX, 4
|
|
SHL ECX, 4
|
|
JZ @PrepSingleLoop
|
|
LEA EAX, [EAX + ECX * 4]
|
|
SHL ECX, 2
|
|
NEG ECX
|
|
|
|
@ChunkLoop:
|
|
//16x unrolled loop
|
|
OR [EAX + ECX], EDX
|
|
OR [EAX + ECX + 4], EDX
|
|
OR [EAX + ECX + 8], EDX
|
|
OR [EAX + ECX + 12], EDX
|
|
|
|
OR [EAX + ECX + 16], EDX
|
|
OR [EAX + ECX + 20], EDX
|
|
OR [EAX + ECX + 24], EDX
|
|
OR [EAX + ECX + 28], EDX
|
|
|
|
OR [EAX + ECX + 32], EDX
|
|
OR [EAX + ECX + 36], EDX
|
|
OR [EAX + ECX + 40], EDX
|
|
OR [EAX + ECX + 44], EDX
|
|
|
|
OR [EAX + ECX + 48], EDX
|
|
OR [EAX + ECX + 52], EDX
|
|
OR [EAX + ECX + 56], EDX
|
|
OR [EAX + ECX + 60], EDX
|
|
|
|
ADD ECX, 16 * 4
|
|
JNZ @ChunkLoop
|
|
|
|
@PrepSingleLoop:
|
|
MOV ECX, EBX
|
|
SHR EBX, 4
|
|
SHL EBX, 4
|
|
SUB ECX, EBX
|
|
JZ @PopExit
|
|
|
|
LEA EAX, [EAX + ECX * 4]
|
|
NEG ECX
|
|
|
|
@SingleLoop:
|
|
OR [EAX + ECX * 4], EDX
|
|
INC ECX
|
|
JNZ @SingleLoop
|
|
|
|
@PopExit:
|
|
POP EBX
|
|
|
|
@Exit:
|
|
{$ENDIF}
|
|
|
|
{$IFDEF TARGET_x64}
|
|
TEST R8D, R8D
|
|
JZ @Exit
|
|
|
|
MOV EAX, R8D
|
|
SHR R8D, 4
|
|
SHL R8D, 4
|
|
JZ @PrepSingleLoop
|
|
LEA RCX, [RCX + R8D * 4]
|
|
SHL R8D, 2
|
|
NEG R8D
|
|
|
|
@ChunkLoop:
|
|
//16x unrolled loop
|
|
OR [RCX + R8D], EDX
|
|
OR [RCX + R8D + 4], EDX
|
|
OR [RCX + R8D + 8], EDX
|
|
OR [RCX + R8D + 12], EDX
|
|
|
|
OR [RCX + R8D + 16], EDX
|
|
OR [RCX + R8D + 20], EDX
|
|
OR [RCX + R8D + 24], EDX
|
|
OR [RCX + R8D + 28], EDX
|
|
|
|
OR [RCX + R8D + 32], EDX
|
|
OR [RCX + R8D + 36], EDX
|
|
OR [RCX + R8D + 40], EDX
|
|
OR [RCX + R8D + 44], EDX
|
|
|
|
OR [RCX + R8D + 48], EDX
|
|
OR [RCX + R8D + 52], EDX
|
|
OR [RCX + R8D + 56], EDX
|
|
OR [RCX + R8D + 60], EDX
|
|
|
|
ADD R8D, 16 * 4
|
|
JNZ @ChunkLoop
|
|
|
|
@PrepSingleLoop:
|
|
MOV R8D, EAX
|
|
SHR EAX, 4
|
|
SHL EAX, 4
|
|
SUB R8D, EAX
|
|
JZ @Exit
|
|
|
|
LEA RCX, [RCX + R8D * 4]
|
|
NEG R8D
|
|
|
|
@SingleLoop:
|
|
OR [RCX + R8D * 4], EDX
|
|
INC R8D
|
|
JNZ @SingleLoop
|
|
|
|
@Exit:
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure AndLine_ASM(Dst: PColor32; Mask: TColor32; Count: Integer);
|
|
// No speedup achieveable using MMX
|
|
asm
|
|
{$IFDEF TARGET_x86}
|
|
TEST ECX, ECX
|
|
JZ @Exit
|
|
|
|
PUSH EBX
|
|
MOV EBX, ECX
|
|
SHR ECX, 4
|
|
SHL ECX, 4
|
|
JZ @PrepSingleLoop
|
|
LEA EAX, [EAX + ECX * 4]
|
|
SHL ECX, 2
|
|
NEG ECX
|
|
|
|
@ChunkLoop:
|
|
//16x unrolled loop
|
|
AND [EAX + ECX], EDX
|
|
AND [EAX + ECX + 4], EDX
|
|
AND [EAX + ECX + 8], EDX
|
|
AND [EAX + ECX + 12], EDX
|
|
|
|
AND [EAX + ECX + 16], EDX
|
|
AND [EAX + ECX + 20], EDX
|
|
AND [EAX + ECX + 24], EDX
|
|
AND [EAX + ECX + 28], EDX
|
|
|
|
AND [EAX + ECX + 32], EDX
|
|
AND [EAX + ECX + 36], EDX
|
|
AND [EAX + ECX + 40], EDX
|
|
AND [EAX + ECX + 44], EDX
|
|
|
|
AND [EAX + ECX + 48], EDX
|
|
AND [EAX + ECX + 52], EDX
|
|
AND [EAX + ECX + 56], EDX
|
|
AND [EAX + ECX + 60], EDX
|
|
|
|
ADD ECX, 16 * 4
|
|
JNZ @ChunkLoop
|
|
|
|
@PrepSingleLoop:
|
|
MOV ECX, EBX
|
|
SHR EBX, 4
|
|
SHL EBX, 4
|
|
SUB ECX, EBX
|
|
JZ @PopExit
|
|
|
|
LEA EAX, [EAX + ECX * 4]
|
|
NEG ECX
|
|
|
|
@SingleLoop:
|
|
AND [EAX + ECX * 4], EDX
|
|
INC ECX
|
|
JNZ @SingleLoop
|
|
|
|
@PopExit:
|
|
POP EBX
|
|
|
|
@Exit:
|
|
{$ENDIF}
|
|
|
|
{$IFDEF TARGET_x64}
|
|
TEST R8D, R8D
|
|
JZ @Exit
|
|
|
|
MOV EAX, R8D
|
|
SHR R8D, 4
|
|
SHL R8D, 4
|
|
JZ @PrepSingleLoop
|
|
LEA RCX, [RCX + R8D * 4]
|
|
SHL R8D, 2
|
|
NEG R8D
|
|
|
|
@ChunkLoop:
|
|
//16x unrolled loop
|
|
AND [RCX + R8D], EDX
|
|
AND [RCX + R8D + 4], EDX
|
|
AND [RCX + R8D + 8], EDX
|
|
AND [RCX + R8D + 12], EDX
|
|
|
|
AND [RCX + R8D + 16], EDX
|
|
AND [RCX + R8D + 20], EDX
|
|
AND [RCX + R8D + 24], EDX
|
|
AND [RCX + R8D + 28], EDX
|
|
|
|
AND [RCX + R8D + 32], EDX
|
|
AND [RCX + R8D + 36], EDX
|
|
AND [RCX + R8D + 40], EDX
|
|
AND [RCX + R8D + 44], EDX
|
|
|
|
AND [RCX + R8D + 48], EDX
|
|
AND [RCX + R8D + 52], EDX
|
|
AND [RCX + R8D + 56], EDX
|
|
AND [RCX + R8D + 60], EDX
|
|
|
|
ADD R8D, 16 * 4
|
|
JNZ @ChunkLoop
|
|
|
|
@PrepSingleLoop:
|
|
MOV R8D, EAX
|
|
SHR EAX, 4
|
|
SHL EAX, 4
|
|
SUB R8D, EAX
|
|
JZ @Exit
|
|
|
|
LEA RCX, [RCX + R8D * 4]
|
|
NEG R8D
|
|
|
|
@SingleLoop:
|
|
AND [RCX + R8D * 4], EDX
|
|
INC R8D
|
|
JNZ @SingleLoop
|
|
|
|
@Exit:
|
|
{$ENDIF}
|
|
end;
|
|
|
|
{$ENDIF}
|
|
|
|
{ extended logical mask functions Src -> Dst }
|
|
{ Non - MMX versions}
|
|
|
|
procedure XorLineEx_Pas(Src, Dst: PColor32; Count: Integer; Mask: TColor32);
|
|
var
|
|
SrcRow: PColor32Array absolute Src;
|
|
DstRow: PColor32Array absolute Dst;
|
|
begin
|
|
Inc(Dst, Count);
|
|
Inc(Src, Count);
|
|
Count := - Count;
|
|
repeat
|
|
DstRow[Count] := SrcRow[Count] xor Mask;
|
|
Inc(Count);
|
|
until Count = 0;
|
|
end;
|
|
|
|
procedure OrLineEx_Pas(Src, Dst: PColor32; Count: Integer; Mask: TColor32);
|
|
var
|
|
SrcRow: PColor32Array absolute Src;
|
|
DstRow: PColor32Array absolute Dst;
|
|
begin
|
|
Inc(Dst, Count);
|
|
Inc(Src, Count);
|
|
Count := - Count;
|
|
repeat
|
|
DstRow[Count] := SrcRow[Count] or Mask;
|
|
Inc(Count);
|
|
until Count = 0;
|
|
end;
|
|
|
|
procedure AndLineEx_Pas(Src, Dst: PColor32; Count: Integer; Mask: TColor32);
|
|
var
|
|
SrcRow: PColor32Array absolute Src;
|
|
DstRow: PColor32Array absolute Dst;
|
|
begin
|
|
Inc(Dst, Count);
|
|
Inc(Src, Count);
|
|
Count := - Count;
|
|
repeat
|
|
DstRow[Count] := SrcRow[Count] and Mask;
|
|
Inc(Count);
|
|
until Count = 0;
|
|
end;
|
|
|
|
{$IFNDEF PUREPASCAL}
|
|
|
|
procedure XorLineEx_ASM(Src, Dst: PColor32; Count: Integer; Mask: TColor32);
|
|
asm
|
|
{$IFDEF TARGET_x86}
|
|
PUSH EBX
|
|
PUSH EDI
|
|
|
|
LEA EAX, [EAX + ECX * 4]
|
|
LEA EDX, [EDX + ECX * 4]
|
|
NEG ECX
|
|
JZ @Exit
|
|
|
|
MOV EDI, Mask
|
|
|
|
@Loop:
|
|
MOV EBX, [EAX + ECX * 4]
|
|
XOR EBX, EDI
|
|
MOV [EDX + ECX * 4], EBX
|
|
INC ECX
|
|
JNZ @Loop
|
|
|
|
@Exit:
|
|
POP EDI
|
|
POP EBX
|
|
{$ENDIF}
|
|
|
|
{$IFDEF TARGET_x64}
|
|
LEA RCX, [RCX + R8D * 4]
|
|
LEA RDX, [RDX + R8D * 4]
|
|
NEG R8D
|
|
JZ @Exit
|
|
|
|
@Loop:
|
|
MOV EAX, [RCX + R8D * 4]
|
|
XOR EAX, R9D
|
|
MOV [RDX + R8D * 4], EAX
|
|
INC R8D
|
|
JNZ @Loop
|
|
|
|
@Exit:
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure OrLineEx_ASM(Src, Dst: PColor32; Count: Integer; Mask: TColor32);
|
|
asm
|
|
{$IFDEF TARGET_x86}
|
|
PUSH EBX
|
|
PUSH EDI
|
|
|
|
LEA EAX, [EAX + ECX * 4]
|
|
LEA EDX, [EDX + ECX * 4]
|
|
NEG ECX
|
|
JZ @Exit
|
|
|
|
MOV EDI, Mask
|
|
|
|
@Loop:
|
|
MOV EBX, [EAX + ECX * 4]
|
|
OR EBX, EDI
|
|
MOV [EDX + ECX * 4], EBX
|
|
INC ECX
|
|
JNZ @Loop
|
|
|
|
@Exit:
|
|
|
|
POP EDI
|
|
POP EBX
|
|
{$ENDIF}
|
|
|
|
{$IFDEF TARGET_x64}
|
|
LEA RCX, [RCX + R8D * 4]
|
|
LEA RDX, [RDX + R8D * 4]
|
|
NEG R8D
|
|
JZ @Exit
|
|
|
|
@Loop:
|
|
MOV EBX, [RCX + R8D * 4]
|
|
OR EBX, R9D
|
|
MOV [RDX + R8D * 4], EBX
|
|
INC R8D
|
|
JNZ @Loop
|
|
|
|
@Exit:
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure AndLineEx_ASM(Src, Dst: PColor32; Count: Integer; Mask: TColor32);
|
|
asm
|
|
{$IFDEF TARGET_x86}
|
|
PUSH EBX
|
|
PUSH EDI
|
|
|
|
LEA EAX, [EAX + ECX * 4]
|
|
LEA EDX, [EDX + ECX * 4]
|
|
NEG ECX
|
|
JZ @Exit
|
|
|
|
MOV EDI, Mask
|
|
|
|
@Loop:
|
|
MOV EBX, [EAX + ECX * 4]
|
|
AND EBX, EDI
|
|
MOV [EDX + ECX * 4], EBX
|
|
INC ECX
|
|
JNZ @Loop
|
|
|
|
@Exit:
|
|
|
|
POP EDI
|
|
POP EBX
|
|
{$ENDIF}
|
|
|
|
{$IFDEF TARGET_x64}
|
|
LEA RCX, [RCX + R8D * 4]
|
|
LEA RDX, [RDX + R8D * 4]
|
|
NEG R8D
|
|
JZ @Exit
|
|
|
|
@Loop:
|
|
MOV EAX, [RCX + R8D * 4]
|
|
AND EAX, R9D
|
|
MOV [RDX + R8D * 4], EAX
|
|
INC R8D
|
|
JNZ @Loop
|
|
|
|
@Exit:
|
|
{$ENDIF}
|
|
end;
|
|
|
|
{ MMX versions}
|
|
|
|
{$IFNDEF OMIT_MMX}
|
|
procedure XorLineEx_MMX(Src, Dst: PColor32; Count: Integer; Mask: TColor32);
|
|
//MMX version
|
|
var
|
|
QMask: Int64;
|
|
|
|
asm
|
|
PUSH EBX
|
|
PUSH EDI
|
|
|
|
TEST ECX, ECX
|
|
JZ @Exit
|
|
|
|
MOV EBX, ECX
|
|
SHR ECX, 4
|
|
SHL ECX, 4
|
|
JZ @PrepSingleLoop
|
|
|
|
SAR ECX, 1
|
|
LEA EAX, [EAX + ECX * 8]
|
|
LEA EDX, [EDX + ECX * 8]
|
|
NEG ECX
|
|
|
|
MOVD MM7, MASK
|
|
PUNPCKLDQ MM7, MM7
|
|
MOVQ QMask, MM7
|
|
EMMS
|
|
|
|
@Loop:
|
|
MOVQ MM0, [EAX + ECX * 8]
|
|
MOVQ MM1, [EAX + ECX * 8 + 8]
|
|
MOVQ MM2, [EAX + ECX * 8 + 16]
|
|
MOVQ MM3, [EAX + ECX * 8 + 24]
|
|
MOVQ MM4, [EAX + ECX * 8 + 32]
|
|
MOVQ MM5, [EAX + ECX * 8 + 40]
|
|
MOVQ MM6, [EAX + ECX * 8 + 48]
|
|
MOVQ MM7, [EAX + ECX * 8 + 56]
|
|
|
|
PXOR MM0, QMask
|
|
PXOR MM1, QMask
|
|
PXOR MM2, QMask
|
|
PXOR MM3, QMask
|
|
PXOR MM4, QMask
|
|
PXOR MM5, QMask
|
|
PXOR MM6, QMask
|
|
PXOR MM7, QMask
|
|
|
|
MOVQ [EDX + ECX * 8], MM0
|
|
MOVQ [EDX + ECX * 8 + 8], MM1
|
|
MOVQ [EDX + ECX * 8 + 16], MM2
|
|
MOVQ [EDX + ECX * 8 + 24], MM3
|
|
MOVQ [EDX + ECX * 8 + 32], MM4
|
|
MOVQ [EDX + ECX * 8 + 40], MM5
|
|
MOVQ [EDX + ECX * 8 + 48], MM6
|
|
MOVQ [EDX + ECX * 8 + 56], MM7
|
|
|
|
ADD ECX, 8
|
|
JS @Loop
|
|
|
|
EMMS
|
|
|
|
@PrepSingleLoop:
|
|
MOV ECX, EBX
|
|
SHR EBX, 4
|
|
SHL EBX, 4
|
|
SUB ECX, EBX
|
|
JZ @Exit
|
|
|
|
LEA EAX, [EAX + ECX * 4]
|
|
LEA EDX, [EDX + ECX * 4]
|
|
NEG ECX
|
|
|
|
MOV EDI, Mask
|
|
|
|
@SingleLoop:
|
|
MOV EBX, [EAX + ECX * 4]
|
|
XOR EBX, EDI
|
|
MOV [EDX + ECX * 4], EBX
|
|
INC ECX
|
|
JNZ @SingleLoop
|
|
|
|
@Exit:
|
|
POP EDI
|
|
POP EBX
|
|
end;
|
|
|
|
procedure OrLineEx_MMX(Src, Dst: PColor32; Count: Integer; Mask: TColor32);
|
|
//MMX version
|
|
var
|
|
QMask: Int64;
|
|
|
|
asm
|
|
PUSH EBX
|
|
PUSH EDI
|
|
|
|
TEST ECX, ECX
|
|
JZ @Exit
|
|
|
|
MOV EBX, ECX
|
|
SHR ECX, 4
|
|
SHL ECX, 4
|
|
JZ @PrepSingleLoop
|
|
|
|
SAR ECX, 1
|
|
LEA EAX, [EAX + ECX * 8]
|
|
LEA EDX, [EDX + ECX * 8]
|
|
NEG ECX
|
|
|
|
MOVD MM7, MASK
|
|
PUNPCKLDQ MM7, MM7
|
|
MOVQ QMask, MM7
|
|
EMMS
|
|
|
|
@Loop:
|
|
MOVQ MM0, [EAX + ECX * 8]
|
|
MOVQ MM1, [EAX + ECX * 8 + 8]
|
|
MOVQ MM2, [EAX + ECX * 8 + 16]
|
|
MOVQ MM3, [EAX + ECX * 8 + 24]
|
|
MOVQ MM4, [EAX + ECX * 8 + 32]
|
|
MOVQ MM5, [EAX + ECX * 8 + 40]
|
|
MOVQ MM6, [EAX + ECX * 8 + 48]
|
|
MOVQ MM7, [EAX + ECX * 8 + 56]
|
|
|
|
POR MM0, QMask
|
|
POR MM1, QMask
|
|
POR MM2, QMask
|
|
POR MM3, QMask
|
|
POR MM4, QMask
|
|
POR MM5, QMask
|
|
POR MM6, QMask
|
|
POR MM7, QMask
|
|
|
|
MOVQ [EDX + ECX * 8], MM0
|
|
MOVQ [EDX + ECX * 8 + 8], MM1
|
|
MOVQ [EDX + ECX * 8 + 16], MM2
|
|
MOVQ [EDX + ECX * 8 + 24], MM3
|
|
MOVQ [EDX + ECX * 8 + 32], MM4
|
|
MOVQ [EDX + ECX * 8 + 40], MM5
|
|
MOVQ [EDX + ECX * 8 + 48], MM6
|
|
MOVQ [EDX + ECX * 8 + 56], MM7
|
|
|
|
ADD ECX, 8
|
|
JS @Loop
|
|
|
|
EMMS
|
|
|
|
@PrepSingleLoop:
|
|
MOV ECX, EBX
|
|
SHR EBX, 4
|
|
SHL EBX, 4
|
|
SUB ECX, EBX
|
|
JZ @Exit
|
|
|
|
LEA EAX, [EAX + ECX * 4]
|
|
LEA EDX, [EDX + ECX * 4]
|
|
NEG ECX
|
|
|
|
MOV EDI, Mask
|
|
|
|
@SingleLoop:
|
|
MOV EBX, [EAX + ECX * 4]
|
|
OR EBX, EDI
|
|
MOV [EDX + ECX * 4], EBX
|
|
INC ECX
|
|
JNZ @SingleLoop
|
|
|
|
@Exit:
|
|
POP EDI
|
|
POP EBX
|
|
end;
|
|
|
|
procedure AndLineEx_MMX(Src, Dst: PColor32; Count: Integer; Mask: TColor32);
|
|
//MMX version
|
|
var
|
|
QMask: Int64;
|
|
asm
|
|
PUSH EBX
|
|
PUSH EDI
|
|
|
|
TEST ECX, ECX
|
|
JZ @Exit
|
|
|
|
MOV EBX, ECX
|
|
SHR ECX, 4
|
|
SHL ECX, 4
|
|
JZ @PrepSingleLoop
|
|
|
|
SAR ECX, 1
|
|
LEA EAX, [EAX + ECX * 8]
|
|
LEA EDX, [EDX + ECX * 8]
|
|
NEG ECX
|
|
|
|
MOVD MM7, MASK
|
|
PUNPCKLDQ MM7, MM7
|
|
MOVQ QMask, MM7
|
|
EMMS
|
|
|
|
@Loop:
|
|
MOVQ MM0, [EAX + ECX * 8]
|
|
MOVQ MM1, [EAX + ECX * 8 + 8]
|
|
MOVQ MM2, [EAX + ECX * 8 + 16]
|
|
MOVQ MM3, [EAX + ECX * 8 + 24]
|
|
MOVQ MM4, [EAX + ECX * 8 + 32]
|
|
MOVQ MM5, [EAX + ECX * 8 + 40]
|
|
MOVQ MM6, [EAX + ECX * 8 + 48]
|
|
MOVQ MM7, [EAX + ECX * 8 + 56]
|
|
|
|
PAND MM0, QMask
|
|
PAND MM1, QMask
|
|
PAND MM2, QMask
|
|
PAND MM3, QMask
|
|
PAND MM4, QMask
|
|
PAND MM5, QMask
|
|
PAND MM6, QMask
|
|
PAND MM7, QMask
|
|
|
|
MOVQ [EDX + ECX * 8], MM0
|
|
MOVQ [EDX + ECX * 8 + 8], MM1
|
|
MOVQ [EDX + ECX * 8 + 16], MM2
|
|
MOVQ [EDX + ECX * 8 + 24], MM3
|
|
MOVQ [EDX + ECX * 8 + 32], MM4
|
|
MOVQ [EDX + ECX * 8 + 40], MM5
|
|
MOVQ [EDX + ECX * 8 + 48], MM6
|
|
MOVQ [EDX + ECX * 8 + 56], MM7
|
|
|
|
ADD ECX, 8
|
|
JS @Loop
|
|
|
|
EMMS
|
|
|
|
@PrepSingleLoop:
|
|
MOV ECX, EBX
|
|
SHR EBX, 4
|
|
SHL EBX, 4
|
|
SUB ECX, EBX
|
|
JZ @Exit
|
|
|
|
LEA EAX, [EAX + ECX * 4]
|
|
LEA EDX, [EDX + ECX * 4]
|
|
NEG ECX
|
|
|
|
MOV EDI, Mask
|
|
|
|
@SingleLoop:
|
|
MOV EBX, [EAX + ECX * 4]
|
|
AND EBX, EDI
|
|
MOV [EDX + ECX * 4], EBX
|
|
INC ECX
|
|
JNZ @SingleLoop
|
|
|
|
@Exit:
|
|
POP EDI
|
|
POP EBX
|
|
end;
|
|
|
|
{ Extended MMX versions}
|
|
|
|
procedure XorLineEx_EMMX(Src, Dst: PColor32; Count: Integer; Mask: TColor32);
|
|
//EMMX version
|
|
var
|
|
QMask: Int64;
|
|
|
|
asm
|
|
PUSH EBX
|
|
PUSH EDI
|
|
|
|
TEST ECX, ECX
|
|
JZ @Exit
|
|
|
|
MOV EBX, ECX
|
|
SHR ECX, 4
|
|
SHL ECX, 4
|
|
JZ @PrepSingleLoop
|
|
|
|
SAR ECX, 1
|
|
LEA EAX, [EAX + ECX * 8]
|
|
LEA EDX, [EDX + ECX * 8]
|
|
NEG ECX
|
|
|
|
MOVD MM7, MASK
|
|
PUNPCKLDQ MM7, MM7
|
|
MOVQ QMask, MM7
|
|
EMMS
|
|
|
|
@Loop:
|
|
MOVQ MM0, [EAX + ECX * 8]
|
|
MOVQ MM1, [EAX + ECX * 8 + 8]
|
|
MOVQ MM2, [EAX + ECX * 8 + 16]
|
|
MOVQ MM3, [EAX + ECX * 8 + 24]
|
|
MOVQ MM4, [EAX + ECX * 8 + 32]
|
|
MOVQ MM5, [EAX + ECX * 8 + 40]
|
|
MOVQ MM6, [EAX + ECX * 8 + 48]
|
|
MOVQ MM7, [EAX + ECX * 8 + 56]
|
|
|
|
PXOR MM0, QMask
|
|
PXOR MM1, QMask
|
|
PXOR MM2, QMask
|
|
PXOR MM3, QMask
|
|
PXOR MM4, QMask
|
|
PXOR MM5, QMask
|
|
PXOR MM6, QMask
|
|
PXOR MM7, QMask
|
|
|
|
MOVNTQ [EDX + ECX * 8], MM0
|
|
MOVNTQ [EDX + ECX * 8 + 8], MM1
|
|
MOVNTQ [EDX + ECX * 8 + 16], MM2
|
|
MOVNTQ [EDX + ECX * 8 + 24], MM3
|
|
MOVNTQ [EDX + ECX * 8 + 32], MM4
|
|
MOVNTQ [EDX + ECX * 8 + 40], MM5
|
|
MOVNTQ [EDX + ECX * 8 + 48], MM6
|
|
MOVNTQ [EDX + ECX * 8 + 56], MM7
|
|
|
|
ADD ECX, 8
|
|
JS @Loop
|
|
|
|
EMMS
|
|
|
|
@PrepSingleLoop:
|
|
MOV ECX, EBX
|
|
SHR EBX, 4
|
|
SHL EBX, 4
|
|
SUB ECX, EBX
|
|
JZ @Exit
|
|
|
|
LEA EAX, [EAX + ECX * 4]
|
|
LEA EDX, [EDX + ECX * 4]
|
|
NEG ECX
|
|
|
|
MOV EDI, Mask
|
|
|
|
@SingleLoop:
|
|
MOV EBX, [EAX + ECX * 4]
|
|
XOR EBX, EDI
|
|
MOV [EDX + ECX * 4], EBX
|
|
INC ECX
|
|
JNZ @SingleLoop
|
|
|
|
@Exit:
|
|
POP EDI
|
|
POP EBX
|
|
end;
|
|
|
|
procedure OrLineEx_EMMX(Src, Dst: PColor32; Count: Integer; Mask: TColor32);
|
|
//EMMX version
|
|
var
|
|
QMask: Int64;
|
|
|
|
asm
|
|
PUSH EBX
|
|
PUSH EDI
|
|
|
|
TEST ECX, ECX
|
|
JZ @Exit
|
|
|
|
MOV EBX, ECX
|
|
SHR ECX, 4
|
|
SHL ECX, 4
|
|
JZ @PrepSingleLoop
|
|
|
|
SAR ECX, 1
|
|
LEA EAX, [EAX + ECX * 8]
|
|
LEA EDX, [EDX + ECX * 8]
|
|
NEG ECX
|
|
|
|
MOVD MM7, MASK
|
|
PUNPCKLDQ MM7, MM7
|
|
MOVQ QMask, MM7
|
|
EMMS
|
|
|
|
@Loop:
|
|
MOVQ MM0, [EAX + ECX * 8]
|
|
MOVQ MM1, [EAX + ECX * 8 + 8]
|
|
MOVQ MM2, [EAX + ECX * 8 + 16]
|
|
MOVQ MM3, [EAX + ECX * 8 + 24]
|
|
MOVQ MM4, [EAX + ECX * 8 + 32]
|
|
MOVQ MM5, [EAX + ECX * 8 + 40]
|
|
MOVQ MM6, [EAX + ECX * 8 + 48]
|
|
MOVQ MM7, [EAX + ECX * 8 + 56]
|
|
|
|
POR MM0, QMask
|
|
POR MM1, QMask
|
|
POR MM2, QMask
|
|
POR MM3, QMask
|
|
POR MM4, QMask
|
|
POR MM5, QMask
|
|
POR MM6, QMask
|
|
POR MM7, QMask
|
|
|
|
MOVNTQ [EDX + ECX * 8], MM0
|
|
MOVNTQ [EDX + ECX * 8 + 8], MM1
|
|
MOVNTQ [EDX + ECX * 8 + 16], MM2
|
|
MOVNTQ [EDX + ECX * 8 + 24], MM3
|
|
MOVNTQ [EDX + ECX * 8 + 32], MM4
|
|
MOVNTQ [EDX + ECX * 8 + 40], MM5
|
|
MOVNTQ [EDX + ECX * 8 + 48], MM6
|
|
MOVNTQ [EDX + ECX * 8 + 56], MM7
|
|
|
|
ADD ECX, 8
|
|
JS @Loop
|
|
|
|
EMMS
|
|
|
|
@PrepSingleLoop:
|
|
MOV ECX, EBX
|
|
SHR EBX, 4
|
|
SHL EBX, 4
|
|
SUB ECX, EBX
|
|
JZ @Exit
|
|
|
|
LEA EAX, [EAX + ECX * 4]
|
|
LEA EDX, [EDX + ECX * 4]
|
|
NEG ECX
|
|
|
|
MOV EDI, Mask
|
|
|
|
@SingleLoop:
|
|
MOV EBX, [EAX + ECX * 4]
|
|
OR EBX, EDI
|
|
MOV [EDX + ECX * 4], EBX
|
|
INC ECX
|
|
JNZ @SingleLoop
|
|
|
|
@Exit:
|
|
POP EDI
|
|
POP EBX
|
|
end;
|
|
|
|
procedure AndLineEx_EMMX(Src, Dst: PColor32; Count: Integer; Mask: TColor32);
|
|
//EMMX version
|
|
var
|
|
QMask: Int64;
|
|
|
|
asm
|
|
PUSH EBX
|
|
PUSH EDI
|
|
|
|
TEST ECX, ECX
|
|
JZ @Exit
|
|
|
|
MOV EBX, ECX
|
|
SHR ECX, 4
|
|
SHL ECX, 4
|
|
JZ @PrepSingleLoop
|
|
|
|
SAR ECX, 1
|
|
LEA EAX, [EAX + ECX * 8]
|
|
LEA EDX, [EDX + ECX * 8]
|
|
NEG ECX
|
|
|
|
MOVD MM7, MASK
|
|
PUNPCKLDQ MM7, MM7
|
|
MOVQ QMask, MM7
|
|
EMMS
|
|
|
|
@Loop:
|
|
MOVQ MM0, [EAX + ECX * 8]
|
|
MOVQ MM1, [EAX + ECX * 8 + 8]
|
|
MOVQ MM2, [EAX + ECX * 8 + 16]
|
|
MOVQ MM3, [EAX + ECX * 8 + 24]
|
|
MOVQ MM4, [EAX + ECX * 8 + 32]
|
|
MOVQ MM5, [EAX + ECX * 8 + 40]
|
|
MOVQ MM6, [EAX + ECX * 8 + 48]
|
|
MOVQ MM7, [EAX + ECX * 8 + 56]
|
|
|
|
PAND MM0, QMask
|
|
PAND MM1, QMask
|
|
PAND MM2, QMask
|
|
PAND MM3, QMask
|
|
PAND MM4, QMask
|
|
PAND MM5, QMask
|
|
PAND MM6, QMask
|
|
PAND MM7, QMask
|
|
|
|
MOVNTQ [EDX + ECX * 8], MM0
|
|
MOVNTQ [EDX + ECX * 8 + 8], MM1
|
|
MOVNTQ [EDX + ECX * 8 + 16], MM2
|
|
MOVNTQ [EDX + ECX * 8 + 24], MM3
|
|
MOVNTQ [EDX + ECX * 8 + 32], MM4
|
|
MOVNTQ [EDX + ECX * 8 + 40], MM5
|
|
MOVNTQ [EDX + ECX * 8 + 48], MM6
|
|
MOVNTQ [EDX + ECX * 8 + 56], MM7
|
|
|
|
ADD ECX, 8
|
|
JS @Loop
|
|
|
|
EMMS
|
|
|
|
@PrepSingleLoop:
|
|
MOV ECX, EBX
|
|
SHR EBX, 4
|
|
SHL EBX, 4
|
|
SUB ECX, EBX
|
|
JZ @Exit
|
|
|
|
LEA EAX, [EAX + ECX * 4]
|
|
LEA EDX, [EDX + ECX * 4]
|
|
NEG ECX
|
|
|
|
MOV EDI, Mask
|
|
|
|
@SingleLoop:
|
|
MOV EBX, [EAX + ECX * 4]
|
|
AND EBX, EDI
|
|
MOV [EDX + ECX * 4], EBX
|
|
INC ECX
|
|
JNZ @SingleLoop
|
|
|
|
@Exit:
|
|
POP EDI
|
|
POP EBX
|
|
end;
|
|
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
|
|
{CPU target and feature Function templates}
|
|
|
|
const
|
|
FID_ANDLINE = 0;
|
|
FID_ORLINE = 1;
|
|
FID_XORLINE = 2;
|
|
FID_ANDLINEEX = 3;
|
|
FID_ORLINEEX = 4;
|
|
FID_XORLINEEX = 5;
|
|
|
|
var
|
|
Registry: TFunctionRegistry;
|
|
|
|
procedure RegisterBindings;
|
|
begin
|
|
Registry := NewRegistry('GR32_Filters bindings');
|
|
Registry.RegisterBinding(FID_ANDLINE, @@LogicalMaskLineAnd);
|
|
Registry.RegisterBinding(FID_ORLINE, @@LogicalMaskLineOr);
|
|
Registry.RegisterBinding(FID_XORLINE, @@LogicalMaskLineXor);
|
|
Registry.RegisterBinding(FID_ANDLINEEX, @@LogicalMaskLineAndEx);
|
|
Registry.RegisterBinding(FID_ORLINEEX, @@LogicalMaskLineOrEx);
|
|
Registry.RegisterBinding(FID_XORLINEEX, @@LogicalMaskLineXorEx);
|
|
|
|
Registry.Add(FID_ANDLINE, @AndLine_Pas);
|
|
Registry.Add(FID_ORLINE, @OrLine_Pas);
|
|
Registry.Add(FID_XORLINE, @XorLine_Pas);
|
|
Registry.Add(FID_ANDLINEEX, @AndLineEx_Pas);
|
|
Registry.Add(FID_ORLINEEX, @OrLineEx_Pas);
|
|
Registry.Add(FID_XORLINEEX, @XorLineEx_Pas);
|
|
|
|
{$IFNDEF PUREPASCAL}
|
|
Registry.Add(FID_ANDLINE, @AndLine_ASM);
|
|
Registry.Add(FID_ORLINE, @OrLine_ASM);
|
|
Registry.Add(FID_XORLINE, @XorLine_ASM);
|
|
Registry.Add(FID_ANDLINEEX, @AndLineEx_ASM);
|
|
Registry.Add(FID_ORLINEEX, @OrLineEx_ASM);
|
|
Registry.Add(FID_XORLINEEX, @XorLineEx_ASM);
|
|
{$IFNDEF OMIT_MMX}
|
|
Registry.Add(FID_ANDLINEEX, @AndLineEx_MMX, [ciMMX]);
|
|
Registry.Add(FID_ORLINEEX, @OrLineEx_MMX, [ciMMX]);
|
|
Registry.Add(FID_XORLINEEX, @XorLineEx_MMX, [ciMMX]);
|
|
Registry.Add(FID_ANDLINEEX, @AndLineEx_EMMX, [ciEMMX]);
|
|
Registry.Add(FID_ORLINEEX, @OrLineEx_EMMX, [ciEMMX]);
|
|
Registry.Add(FID_XORLINEEX, @XorLineEx_EMMX, [ciEMMX]);
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
|
|
Registry.RebindAll;
|
|
end;
|
|
|
|
initialization
|
|
RegisterBindings;
|
|
|
|
end.
|