Entwickler-Ecke
Algorithmen, Optimierung und Assembler - Alphablending-Delphicode beschleunigen (ev. mit Assembler?)
SixpointedStarsoft - Sa 02.01.10 11:06
Titel: Alphablending-Delphicode beschleunigen (ev. mit Assembler?)
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:
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 $00FF0000) shr 16; GU := (FarbeUntere and $0000FF00) shr 8; BU := FarbeUntere and $000000FF;
AO := (FarbeObere shr 24)/255*AlphablendingWert; RO := (FarbeObere and $00FF0000) shr 16; GO := (FarbeObere and $0000FF00) shr 8; BO := FarbeObere and $000000FF;
antiAlpha := 1 - AO; NeuerAlphaWert := AO+AU - AO * AU; A3:= Round(255*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 - Sa 02.01.10 11: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.
Delete - Sa 02.01.10 11: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 - Sa 02.01.10 12:51
Gausi hat folgendes geschrieben : |
| 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:
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; nXOriginDest: integer; nYOriginDest: integer; nWidthDest: integer; nHeightDest: integer; const BmpSrc: TBitmap32; nXOriginSrc: integer; nYOriginSrc: integer; nWidthSrc: integer; 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] <>0) then if ((P[nXOriginSrc+X] shr 24) <> 255) then 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 - Sa 02.01.10 13: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 - Sa 02.01.10 13:14
jaenicke hat folgendes geschrieben : |
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:
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 - Sa 02.01.10 14: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.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!