Autor Beitrag
SixpointedStarsoft
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 22
Erhaltene Danke: 1



BeitragVerfasst: Sa 02.01.10 12:06 
Hallo Zusammen

Ich habe ein Coloralphablending geschrieben, das heisst ein oberer und ein unterer Farbepixel mittels einer Blendfunktion vermischen, wie dies Windows.Alphablend macht. Der Code funktioniert, möchte ihn aber beschleunigen. Assembler wäre eine Möglichkeit, leider beherrsche ich das nicht. Meine Fragen sind also:
• Hat jemand eine Idee, wie man den Delphicode verbessern kann?
• Hat jemand Kentnisse, wie man das in Assembler schreiben könnte? (Oder dauert das lange dies zu erlernen?)

Hier der Code:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
procedure ColorAlphablending(var FarbeUntere: TColor32; FarbeObere : TColor32; AlphablendingWert:Real);
    function ToColor32(R, G, B: Byte; A: Byte = $FF): TColor32;
    asm
            MOV  AH,A
            SHL  EAX,16
            MOV  AH,DL
            MOV  AL,CL
    end;
  var
     RU,GU,BU,RO,GO,BO : Byte;
     AU,AO: real;
     NeuerAlphaWert: real;
     antiAlpha: real;
     A3: byte;

  begin
    AU := (FarbeUntere shr 24)/255;
    RU := (FarbeUntere and $00FF0000shr 16;
    GU := (FarbeUntere and $0000FF00shr 8;
    BU := FarbeUntere and $000000FF;

    AO := (FarbeObere shr 24)/255*AlphablendingWert;
    RO := (FarbeObere and $00FF0000shr 16;
    GO := (FarbeObere and $0000FF00shr 8;
    BO := FarbeObere and $000000FF;


    // Alphablend   http://en.wikipedia.org/wiki/Alpha_compositing
    antiAlpha := 1 - AO;
    NeuerAlphaWert := AO+AU - AO * AU;
  //  NeuerAlphaWert := 1-(1- AU)* (1-AU);
  //  NeuerAlphaWert := (AO+AU*(1- AO))*AlphablendingWert;

    A3:= Round(255*NeuerAlphaWert);
    (*
    RU := Round(( RO * AO    + RU * AU * antiAlpha ) / NeuerAlphaWert);
    BU := Round(( BO * AO    + BU * AU * antiAlpha ) / NeuerAlphaWert);
    GU := Round(( GO * AO    + GU * AU * antiAlpha ) / NeuerAlphaWert);
      *)



    RU := Round(antiAlpha*RU+ NeuerAlphaWert*RO);
    BU := Round(antiAlpha*BU+ NeuerAlphaWert*BO);
    GU := Round(antiAlpha*GU+ NeuerAlphaWert*GO);

    FarbeUntere:=ToColor32(RU,GU,BU,A3);
  end;
Gausi
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8548
Erhaltene Danke: 477

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: Sa 02.01.10 12:28 
Wie rufst du denn die Funktion auf? Denn die macht das ja pixelweise. Wenn du über Canvas.Pixels iterierst, dann liegt da der (sehr deutliche) Flaschenhals.

_________________
We are, we were and will not be.
j.klugmann
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Sa 02.01.10 12:30 
Noch eine Möglichkeit wäre , SSE statt normales Assembler zu nehmen.Gausi hat aber recht , durch SSE wird es dann auch nicht viel schneller.
SixpointedStarsoft Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 22
Erhaltene Danke: 1



BeitragVerfasst: Sa 02.01.10 13:51 
user profile iconGausi hat folgendes geschrieben Zum zitierten Posting springen:
Wie rufst du denn die Funktion auf? Denn die macht das ja pixelweise. Wenn du über Canvas.Pixels iterierst, dann liegt da der (sehr deutliche) Flaschenhals.


Also ich rufe die Procedur wie folgt auf:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
procedure CopyTo( const BmpDest: TBitmap32;                 // handle to destination DC
                    nXOriginDest: integer;            // x-coord of upper-left corner
                    nYOriginDest: integer;            // y-coord of upper-left corner
                    nWidthDest: integer;              // destination width
                    nHeightDest: integer;             // destination height
                    const BmpSrc: TBitmap32;                  // handle to source DC
                    nXOriginSrc: integer;             // x-coord of upper-left corner
                    nYOriginSrc: integer;             // y-coord of upper-left corner
                    nWidthSrc: integer;               // source width
                    nHeightSrc: integer);
  var
    X,Y,W: Integer;
    P, PDest: PColor32Array;
  begin
    W:= BmpDest.Width;
    for Y := 0 to nHeightSrc-1 do begin

      P := @BmpSrc.Bits[(nYOriginSrc+Y) * BmpSrc.Width];
      PDest:= @BmpDest.Bits[(nYOriginDest+Y) * W];

      for X := 0 to nWidthSrc - 1 do
        if P[nXOriginSrc+X] <> 0 then
          if (PDest[nXOriginDest + X] <>0then
            if ((P[nXOriginSrc+X] shr 24) <> 255then
              ColorAlphablending(PDest[nXOriginDest + X],P[nXOriginSrc+X],1)
            else
              PDest[nXOriginDest + X]:= P[nXOriginSrc+X]
          else
            PDest[nXOriginDest + X]:= P[nXOriginSrc+X];
    end;
  end;
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Sa 02.01.10 14:01 
Wenn du ScanLine benutzt, dann sparst du dir die ganzen Arrayzugriffe. Auch wenn der Geschwindigkeitszuwachs vermutlich nicht so hoch wie beim originalen TBitmap ist, denke ich trotzdem, dass es etwas bringen kann.

Und da du ohnehin schon mit Pointern arbeitest, ist das ja auch nicht mehr so viel anders.
SixpointedStarsoft Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 22
Erhaltene Danke: 1



BeitragVerfasst: Sa 02.01.10 14:14 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Wenn du ScanLine benutzt, dann sparst du dir die ganzen Arrayzugriffe. Auch wenn der Geschwindigkeitszuwachs vermutlich nicht so hoch wie beim originalen TBitmap ist, denke ich trotzdem, dass es etwas bringen kann.

Und da du ohnehin schon mit Pointern arbeitest, ist das ja auch nicht mehr so viel anders.


Scanline macht nichts anderes, denn scanline ist wie folgt aufgebaut:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
function TBitmap32.GetScanLine(Y: Integer): PColor32Array;
begin
  Result := @Bits[Y * FWidth];
end;


desshalb habe ich daruaf versichtet diese Funktion aufzurufen, da dies schon wieder mehr Zeit in Anspruch nimmt. Nach meiner Zeitmessung schnellt, mit jedem solchen Aufruf die Zeit in die Höhe.
Im Moment arbeitet diese Procedure schneller als das Windows.Alphablend es tut (natürlich in der Art und Weise wie ich es gebrauche mit meinen Bildern). Sobald aber alle Pixel "geblendet werden müssen" ist Windows schneller.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Sa 02.01.10 15:03 
Gut, dann natürlich nicht, aber worauf ich vor allem hinauswollte sind ja die Arrayzugriffe. Du musst doch nur jeweils den Pointer verschieben statt jedesmal wieder die Position im Array anzusprechen. Denn genau das macht die Scanline-Verwendung bei der normalen TBitmap ja schnell.