![]() |
AW: Geht das noch schneller? - Bitmap-Verrechnung
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
Die einzige Verwendung der hier diskutierten Funktion im Programm ist die Anzeige des fertig verrechneten Bitmap-Ebenen-Stapels auf einen Karo-Hintergrund (siehe anliegenden Screenshot). Ich verwende übrigens dafür nicht die Windows Alphablend-Funktion, da die für bestimmte Bilder fehlerhafte Ergebnisse berechnet (eigentlich schade, denn die ist noch schneller, als die Funktion hier). Insofern stellt die hier diskutierte Funktion einen (Teil-)Ersatz dafür dar. |
AW: Geht das noch schneller? - Bitmap-Verrechnung
Zitat:
Werde ich mir mal ansehen. Gibt es dort so eine spezielle Verrechnungsfunktion wie hier benötigt? |
AW: Geht das noch schneller? - Bitmap-Verrechnung
Alpha-Blending würde ich nun nicht wirklich als speziell bezeichnen, daher ja: Die Graphics32 bietet eine Fülle an Möglichkeiten diesbezüglich. Sogar direkten Support für Layers in Bitmaps (mit den respektiven Kombinationsfunktionen, u.a. standard Alpha-Blending). Vom Gefühl her würde ich fast sagen, dass diese Lib dein Heiland sein könnte.
|
AW: Geht das noch schneller? - Bitmap-Verrechnung
Zitat:
|
AW: Geht das noch schneller? - Bitmap-Verrechnung
Danke, das war ein wichtiger Hinweis, den ich übersehen hatte: Wenn die Bitmap Premultiplied ist, funktioniert die Alphablend-Funktion auch wie bei allen Bitmaps wie gewünscht!!:oops:
Insgesamt ist dann die Kombination temporäres Premultiplied-Bitmap erzeugen und mit Alphablend benutzen schon schneller als die hier bislang gefundene Lösung. Das hier ist meine aktuelle PreMultiply-Funktion: Kann man das auch noch irgendwie beschleunigen?
Delphi-Quellcode:
procedure PreMultiply (bm: TBitmap); inline;
var y, x: Integer; RGBA: pRGBALine; begin for y := 0 to bm.Height-1 do begin RGBA := bm.Scanline[y]; for x := 0 to bm.Width-1 do begin if (RGBA^[x].rgbReserved <> 0) and (RGBA^[x].rgbReserved <> 255) then begin if RGBA^[x].rgbRed <> 0 then RGBA^[x].rgbRed := round ((RGBA^[x].rgbReserved * RGBA^[x].rgbRed ) / 255); if RGBA^[x].rgbGreen <> 0 then RGBA^[x].rgbGreen := round ((RGBA^[x].rgbReserved * RGBA^[x].rgbGreen ) / 255); if RGBA^[x].rgbBlue <> 0 then RGBA^[x].rgbBlue := round ((RGBA^[x].rgbReserved * RGBA^[x].rgbBlue ) / 255); end; end; end; end; |
AW: Geht das noch schneller? - Bitmap-Verrechnung
Ja, kann man. Einfach die Beiträge durchlesen (Array vs. Pointer, Integer vs. FP mathematik (Stichwort: 'MulDiv')
Du kannst die Ergebnisse der Rechnung auch vorher einmal in einer Matrix vornehmen und dann nur noch auslesen. Dann hast Du einmalig overhead aber bei vielen Berechnungen könnte sich das lohnen, zumal Du wohl auf FP-Mathematik bestehst. Warum auch immer.
Delphi-Quellcode:
var
lkup : Array [0..255, 0..255] of Byte; Begin for i:=0 to 255 do for j:=0 to 255 do lkup[i,j] := round(i*j/255); End; ... for y := 0 to bm.Height-1 do begin RGBA := bm.Scanline[y]; for x := 0 to bm.Width-1 do begin if (RGBA^.rgbReserved <> 0) and (RGBA^.rgbReserved <> 255) then begin if RGBA^.rgbRed <> 0 then RGBA^.rgbRed := lk[RGBA^.rgbReserved , RGBA^.rgbRed]; if RGBA^.rgbGreen <> 0 then RGBA^.rgbGreen := lk[RGBA^.rgbReserved, RGBA^.rgbGreen]; if RGBA^.rgbBlue <> 0 then RGBA^.rgbBlue := lk[RGBA^.rgbReserved, RGBA^.rgbBlue]; end; inc(RGBA); end; end; |
AW: Geht das noch schneller? - Bitmap-Verrechnung
Die inneren Verzweigungen wegzulassen könnte auch noch was bringen:
Delphi-Quellcode:
var
lkup : Array [0..255, 0..255] of Byte; Begin for i:=0 to 255 do for j:=0 to 255 do begin if (j <> 0) and (j <> 255) then // ist j <> 0 überhaupt korrekt hier? lkup[i,j] := round(i*j/255) else lkup[i,j] := j; end; End; ... for y := 0 to bm.Height-1 do begin RGBA := bm.Scanline[y]; for x := 0 to bm.Width-1 do begin RGBA^.rgbRed := lk[RGBA^.rgbReserved , RGBA^.rgbRed]; RGBA^.rgbGreen := lk[RGBA^.rgbReserved, RGBA^.rgbGreen]; RGBA^.rgbBlue := lk[RGBA^.rgbReserved, RGBA^.rgbBlue]; inc(RGBA); end; end; |
AW: Geht das noch schneller? - Bitmap-Verrechnung
Das hatte ich gerade auch zufälligerweise im Internet gefunden.
Doch Überraschung: Ist deutlich langsamer, als meine Funktion, die ich gepostet hatte. Wahrscheinlich kostet der doppelte Zugriff auf das byte-Array mehr Zeit als die direkte Berechnung der Werte. Edit: Halt, diese Aussage muss ich evtl. zurückziehen. Wenn ich folgende logische Abfrage wie bei mir oben einbaue, ist es zumindest ähnlich schnell:
Delphi-Quellcode:
Hängt dann eben davon ab, wieviel Pixel überhaupt Transparent sind, denn nur die müssen ja berechnet werden, die anderen können den Wert behalten.
if RGBA^[x].rgbReserved <> 255 then begin
|
AW: Geht das noch schneller? - Bitmap-Verrechnung
Das Lookup-Array wird nur einmal berechnet, da ist es unerheblich, etwas zu optimieren. Daher würde ich diesen Vorgang nicht in die Performancebetrachtungen mit einbeziehen.
Beim Schreiben des Vorschlags ist mir aber auch aufgefallen, das es bei drei Operationen (*, /, round) nicht allzuviel zu optimieren gibt. Aber wieso verwendest Du 'MulDiv' nicht? Das Ergebnis ist um höchstens 1 unterschiedlich (Rundungsverhalten). |
AW: Geht das noch schneller? - Bitmap-Verrechnung
Zitat:
Aber ein C := A * 5 div B; ist:
Code:
ein C := MULDIV(A,5,B) ist:
xor eax,eax
mov al,[ebp-$5] lea eax,[eax+eax*4] xor edx,edx mov dl,[ebp-$06] mov ecx,edx xor edx,edx div ecx mov edx,[ebp-$04] mov [edx+$002d4],al
Code:
Ein C := A * B div 8 ist:
xor eax,eax
mov al,[ebp-$6] push eax push $05 xor eax,eax mov al,[ebp-$5) Push eax // bishier schon fast so viele Ticks wie oben CALL MulDiv // aus MulDiv jmp dword ptr[$00896ae8] mov eax,[esp+$04} or eax,eax js $75201b80 mov edx,[esp+$80] or edx,edx js $75201c06 mul edx mov ecx,[eps+$0c] or ecx,ecx js $75201c48 sar ecx,1 add eax,ecx adc edx.$00 cmp edx,[esp+$0c] jnb $75201b7a div dword ptr [esp+$0c] or eax,eay js $75201b7a ret $000c mov edx,[ebp-$04] // gleich mit oben mov [edx+$02d4],al // gleich mit oben
Code:
xor eax,eax // gleich mit oben
mov al,[ebp-$05] // gleich mit oben xor edx,edx // gleich mit oben mov dl,[ebp-$06], imul edx shr eax, $03 // div 8 erkannt mov edx,[ebp-$04] // gleich mit oben mov [edx+$02d4],al // gleich mit oben Mavarik |
AW: Geht das noch schneller? - Bitmap-Verrechnung
MulDiv basiert auf In64 und ist damit überlauf-sicher, was bei A*B div C imho nicht der Fall ist. Dafür ist es langsamer als der das einfache A*B DIV C.
Bezüglich des Performancevergleiches zielte ich eher auf 'MulDiv' vs. 'Round(A*B/C)' ab, also Floating Point Arithmetik. |
AW: Geht das noch schneller? - Bitmap-Verrechnung
Zitat:
|
AW: Geht das noch schneller? - Bitmap-Verrechnung
Um die bisherigen Ergebnisse zusammenzufassen:
* Zugriff auf ein Lookup-Array dauert länger, als die Berechnung. * MulDiv bringt eindeutig keine Beschleunigung * Im vorliegenden Fall bringt auch eine Parallelisierung nichts, da der Verwaltungsaufwand größer ist, als der Gewinn durch mehrere Prozessorkerne Das bislang schnellste Ergebnis liefert der untenstehende Code, egal, ob per Pointer-Addition oder Array-Zugriff:
Delphi-Quellcode:
procedure Draw32BitToBitmapxxx(const BitOben: TBitmap; BitUnten: TBitmap); // Array-Zugriff
var h,w,i, r, g, b: Integer; RGBA_Unten, RGBA_Oben: pRGBALine; begin for h := 0 to BitUnten.Height-1 do begin RGBA_Unten := BitUnten.ScanLine[h]; RGBA_Oben := BitOben.ScanLine[h]; For w:= 0 to BitUnten.Width-1 do begin if RGBA_Oben^[w].rgbReserved = 0 then begin // unten bleibt end else begin RGBA_Unten^[w].rgbred := (RGBA_Oben^[w].rgbReserved * (RGBA_Oben^[w].rgbred - RGBA_Unten^[w].rgbred) shr 8 + RGBA_Unten^[w].rgbred); RGBA_Unten^[w].rgbGreen := (RGBA_Oben^[w].rgbReserved * (RGBA_Oben^[w].rgbgreen - RGBA_Unten^[w].rgbGreen) shr 8 + RGBA_Unten^[w].rgbGreen); RGBA_Unten^[w].rgbBlue := (RGBA_Oben^[w].rgbReserved * (RGBA_Oben^[w].rgbBlue - RGBA_Unten^[w].rgbBlue) shr 8 + RGBA_Unten^[w].rgbBlue); RGBA_Unten^[w].rgbReserved := 255; end; end; end; end; procedure Draw32BitToBitmapnew(const BitOben: TBitmap; BitUnten: TBitmap); // Pointer-Addition var h,w: Integer; RGBA_Unten, RGBA_Oben: ^TRGBQuad; // pRGBALine; begin For h := 0 to BitUnten.Height-1 do begin RGBA_Unten := BitUnten.ScanLine[h]; RGBA_Oben := BitOben.ScanLine[h]; For w:= 0 to BitUnten.Width-1 do begin if RGBA_Oben^.rgbReserved = 0 then begin // unten bleibt end else begin RGBA_Unten^.rgbBlue := ((RGBA_Oben^.rgbReserved * (RGBA_Oben^.rgbBlue - RGBA_Unten^.rgbBlue)) shr 8 + RGBA_Unten^.rgbBlue); RGBA_Unten^.rgbGreen := ((RGBA_Oben^.rgbReserved * (RGBA_Oben^.rgbgreen - RGBA_Unten^.rgbGreen)) shr 8 + RGBA_Unten^.rgbGreen); RGBA_Unten^.rgbred := ((RGBA_Oben^.rgbReserved * (RGBA_Oben^.rgbred - RGBA_Unten^.rgbred)) shr 8 + RGBA_Unten^.rgbred); RGBA_Unten^.rgbReserved := 255; end; inc (RGBA_Unten); inc (RGBA_oben); end; end; end; |
AW: Geht das noch schneller? - Bitmap-Verrechnung
Zitat:
Vielleicht über die Parallel FOR ok, kann ich nicht nachvollziehen. Aber einen optimierten thread mit entsprechendem vorbereiteten Prozessen müsste schneller sein. Können wir am Sa. ja mit unserem Thread König, emm Kaiser, ich meine Kaisler diskutieren. :stupid: Mavarik |
AW: Geht das noch schneller? - Bitmap-Verrechnung
Hallo, ich bin hier neu hinzugestoßen und versuche mich am Beschleunigen.
Zuförderst ein paar Fragen zu den Details: ● Ist der Nenner in der Formel 255 oder 256? Bei 255 sind einige Klimmzüge nötig ● Ist Round vonnöten, oder dient es nur zur Float-Integer-Konvertierung? ● Von welcher WEB-Site kann ich 2 repräsentative 32-bittige Bitmaps absaugen? Da ich schon einmal mit MMX-Befehlen Antialiasing veranstaltet habe, würde ich mich gern an der Bitmap-Verrechnung versuchen. MfG Manfred(19)42 |
AW: Geht das noch schneller? - Bitmap-Verrechnung
Zitat:
Muss man quasi im Einzelfall testen, wo was schneller ist. |
AW: Geht das noch schneller? - Bitmap-Verrechnung
Zitat:
Round wäre gut, zur Not aber auch ohne. Erstelle Dir doch einfach selber 2 passende Bitmaps, hier die Größe und Bedingungen, mit denen ich hier teste: - 3548x2558 Pixel, 32 Bit-Format. - Das untere Bitmap hat einen Verlaufsuntergrund, das obere Bitmap hat zwei rechteckige Bereiche (jeweils 340 x 2300), die zu 100% transparent sind. |
AW: Geht das noch schneller? - Bitmap-Verrechnung
Danke für den Ratschlag (um diese Uhrzeit)!
Ich hatte mit 2 kleineren Bitmaps experimentiert und werde dem Ratschlag folgen. Jetzt habe die letzte (Pointer)-Version der Prozedur probiert. Sie läuft sehr flott und schreit förmlich nach dem Einsatz von MMX-Code. An einer Thread-Version will ich mich später versuchen. Ich habe da schon eine Idee. Bei Threads bin ich aber nicht sehr sattelfest. Auf meinem DualCore-Notebook für Rentner wird es nicht viel bringen Wenn ich mit den technischen Rahmenbedingungen der DP mehr vertraut bin, werde ich auch Codepassagen präsentieren. Gute Nacht! |
AW: Geht das noch schneller? - Bitmap-Verrechnung
Delphi-Quellcode:
PROCEDURE Blend32(Source,Dest:pRGBQuad; Width,Height,OOffset,UOffset:Integer);
const RegSize=4; WOffs=6*RegSize; HOffs=12*RegSize; OOffs=11*RegSize; UOffs=10*RegSize; asm pushad mov ebp,ecx // Width lea esi,[eax+ebp*4] // Source lea edi,[edx+ebp*4] // Dest neg ebp mov [esp+WOffs],ebp @Loop: mov bl,[esi+ebp*4].TRgbQuad.rgbReserved // S.Reserved test bl,bl jz @Next // Red mov al,[esi+ebp*4].TRgbQuad.rgbRed // S.Red mov cl,[edi+ebp*4].TRgbQuad.rgbRed // D.Red sub al,cl // S.Red-D.Red imul bl // (S.Red-D.Red)*S.Reserved add ah,cl // ((S.Red-D.Red)*S.Reserved) shr 8 + D.Red mov dx,ax // Green mov al,[esi+ebp*4].TRgbQuad.rgbGreen // S.Green mov cl,[edi+ebp*4].TRgbQuad.rgbGreen // D.Green sub al,cl // S.Green-D.Green imul bl // (S.Green-D.Green)*S.Reserved mov dl,ah // ((S.Green-D.Green)*S.Reserved) shr 8 add dl,cl // ((S.Green-D.Green)*S.Reserved) shr 8 + D.Green shl edx,8 // Blue mov al,[esi+ebp*4].TRgbQuad.rgbBlue // S.Blue mov cl,[edi+ebp*4].TRgbQuad.rgbBlue // D.Blue sub al,cl // S.Blue-D.Blue imul bl // (S.Blue-D.Blue)*S.Reserved mov dl,ah // ((S.Blue-D.Blue)*S.Reserved) shr 8 add dl,cl // ((S.Blue-D.Blue)*S.Reserved) shr 8 + D.Blue // Reserved or edx,$FF000000 mov [edi+ebp*4],edx add ebp,1 jl @Loop // Nächste Zeile @Next: add esi,[esp+OOffs] add edi,[esp+UOffs] mov ebp,[esp+WOffs] sub [esp+HOffs],1 jnz @Loop @End: popad end;
Delphi-Quellcode:
PROCEDURE AsmDraw32BitToBitmap(Source,Dest:TBitmap);
resourcestring sWidthDifferent='Bitmaps haben unterschiedliche Breiten'; sHeightDifferent='Bitmaps haben unterschiedliche Höhen'; sZeroWidth='Breite der Bitmaps ist 0'; sLessTwoLines='Höhe der Bitmaps ist < 2'; sSourceNone32Bit='Source ist keine 32 Bit Bitmap'; sDestNone32Bit='Dest ist keine 32 Bit Bitmap'; var PSource,PDest:pRGBQuad; W,H,SOffset,DOffset:Integer; begin W:=Source.Width; H:=Source.Height; if Dest.Width<>W then raise Exception.Create(sWidthDifferent); if Dest.Height<>H then raise Exception.Create(sHeightDifferent); if W<1 then raise Exception.Create(sZeroWidth); if H<2 then raise Exception.Create(sLessTwoLines); if Source.PixelFormat<>pf32bit then raise Exception.Create(sSourceNone32Bit); if Dest.PixelFormat<>pf32bit then raise Exception.Create(sDestNone32Bit); PSource:=Source.ScanLine[0]; SOffset:=NativeInt(Source.ScanLine[1])-NativeInt(PSource); PDest:=Dest.ScanLine[0]; DOffset:=NativeInt(Dest.ScanLine[1])-NativeInt(PDest); Blend32(PSource,PDest,W,H,SOffset,DOffset); end; |
AW: Geht das noch schneller? - Bitmap-Verrechnung
Zitat:
Wie an anderer Stelle schon dargestellt sollte die Implementierung mit Hilfe von SIMD Befehlen mehr bringen. Wenn Du dabei lieber mit Pascal als mit Assembler arbeitest, dann schau Dir doch mal Vector-Pascal : ![]() ![]() an. Ist zwar schon einige Zeit her das ich damit gespielt habe, aber damals konnte ich damit eine DLL erstellen und die Funktionen in Delphi einbinden und für solche Probleme wie Deines war das Teil ideal. hth HaJoe |
AW: Geht das noch schneller? - Bitmap-Verrechnung
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
Wäre noch etwas schneller als meine letzte Variante (hier zuletzt ca. 62 MS, die ASM ca. 47 MS), allerdings ist das Ergebnis erkennbar falsch, siehe Screenshot). |
AW: Geht das noch schneller? - Bitmap-Verrechnung
[QUOTE=hanvas;1281434]
Zitat:
Die Konsequenz, das ganze Programm umzuschreiben, möchte ich derzeit noch ganz gerne vermeiden... |
AW: Geht das noch schneller? - Bitmap-Verrechnung
Zitat:
cu HaJoe |
AW: Geht das noch schneller? - Bitmap-Verrechnung
Zitat:
Das Label "Next:" gehört 2 Code-Zeilen höher. So wie es war, wurde bei rgbReserved=0 zum nächsten Zeilenanfang gesprungen statt zum nächsten Pixel. Bei meiner Prüfung auf identische Ergebnisse hatte ich dummerweise immer alle rgbReserved<>0, so dass dieser Fehler nicht auftrat.
Delphi-Quellcode:
PROCEDURE Blend32(Source,Dest:pRGBQuad; Width,Height,OOffset,UOffset:Integer);
const RegSize=4; WOffs=6*RegSize; HOffs=12*RegSize; OOffs=11*RegSize; UOffs=10*RegSize; asm pushad mov ebp,ecx // Width lea esi,[eax+ebp*4] // Source lea edi,[edx+ebp*4] // Dest neg ebp mov [esp+WOffs],ebp @Loop: mov bl,[esi+ebp*4].TRgbQuad.rgbReserved // S.Reserved test bl,bl jz @Next // Red mov al,[esi+ebp*4].TRgbQuad.rgbRed // S.Red mov cl,[edi+ebp*4].TRgbQuad.rgbRed // D.Red sub al,cl // S.Red-D.Red imul bl // (S.Red-D.Red)*S.Reserved add ah,cl // ((S.Red-D.Red)*S.Reserved) shr 8 + D.Red mov dx,ax // Green mov al,[esi+ebp*4].TRgbQuad.rgbGreen // S.Green mov cl,[edi+ebp*4].TRgbQuad.rgbGreen // D.Green sub al,cl // S.Green-D.Green imul bl // (S.Green-D.Green)*S.Reserved mov dl,ah // ((S.Green-D.Green)*S.Reserved) shr 8 add dl,cl // ((S.Green-D.Green)*S.Reserved) shr 8 + D.Green shl edx,8 // Blue mov al,[esi+ebp*4].TRgbQuad.rgbBlue // S.Blue mov cl,[edi+ebp*4].TRgbQuad.rgbBlue // D.Blue sub al,cl // S.Blue-D.Blue imul bl // (S.Blue-D.Blue)*S.Reserved mov dl,ah // ((S.Blue-D.Blue)*S.Reserved) shr 8 add dl,cl // ((S.Blue-D.Blue)*S.Reserved) shr 8 + D.Blue // Reserved or edx,$FF000000 mov [edi+ebp*4],edx @Next: add ebp,1 jl @Loop // Nächste Zeile add esi,[esp+OOffs] add edi,[esp+UOffs] mov ebp,[esp+WOffs] sub [esp+HOffs],1 jnz @Loop @End: popad end; |
AW: Geht das noch schneller? - Bitmap-Verrechnung
@Amateurprofi:
Danke, dass Du Dich der Sache noch mal angenommen hast. Allerdings stimmt das Ergebnis immer noch nicht. Falls Du die Sache noch weiter verfolgen willst, kannst Du hier im Thread-Beitrag Nr. 26 das Demoprojekt laden, das ich gepostet habe. Da brauchst Du nur im Button-Click Event folgendes zu machen, um Deine Procedure einzubinden:
Delphi-Quellcode:
Dann Siehst Du direkt im Vergleich, ob beide Bilder den gleichen Inhalt haben.
for L := 1 to count do begin
AsmDraw32BitToBitmap (b, b3); //Draw32BitToBitmapnew (b, b3); end; |
[Gelöst] AW: Geht das noch schneller? - Bitmap-Verrechnung
Ich habe nun den Rat gefolgt und habe mir die Graphics32-Unit mal angehen.
Der Grafk-Typ TBitmap32 ist zwar ein eigener Klassen-Typ, aber die Lowlowel-Routinen, die dahinter liegen, kann man auch auf TBitmap anwenden. Die Lösung besteht also nun darin, GR32 und GR32_Blend aus der Graphics32 einzubinden und dann kann man die Funktion mit einer Zeile (1) benutzen, die dann auch nur noch 31 MS benötigt, um das Bild zu verrechnen:
Delphi-Quellcode:
procedure Draw32BitToBitmap(const BitOben: TBitmap; BitUnten: TBitmap);
begin BLEND_LINE[cmBlend]^(pColor32(BitOben.ScanLine[BitUnten.Height-1]), pColor32(BitUnten.ScanLine[BitUnten.Height-1]), BitUnten.Width* BitUnten.Height); end; |
AW: Geht das noch schneller? - Bitmap-Verrechnung
Zitat:
Habe ich geprüft. Ich habe eine 8Bit-Integer-Multipikation benutzt, bei der Byte-Werte > $7F als negativ betrachtet werden. Im Debugger sah ich dann, dass bei Deiner Prozedur eine 32Bit-Integer Multiplikation verwendet wird. Bei den Tests fiel das nicht ins Gewicht, weil ich einfach den gesamten Screen nach BitOben und BitUnten kopiert hatte. Somit waren die Rgb-Werte in Oben und Unten gleich und die Subtraktion von z.B. Oben.rgbRed - Unten.rgbRed ergab immer 0. Nachdem ich die Bitmaps mit Zufallswerten gefüllt hatte konnte den Grund der Abweichungen finden. Ich habe die Prozedur Blend32 umgeschrieben. Für mich sehr überraschend, ist sie dadurch schneller geworden; ich hatte das Gegenteil erwartet. Dein Beispiel Projekt läßt sich bei mir (XE2) nicht kompilieren.
Delphi-Quellcode:
PROCEDURE Blend32(Source,Dest:pRGBQuad; Width,Height,OOffset,UOffset:Integer);
const RegSize=4; WOffs=6*RegSize; HOffs=12*RegSize; OOffs=11*RegSize; UOffs=10*RegSize; asm pushad lea esi,[eax+ecx*4] // Source lea edi,[edx+ecx*4] // Dest neg ecx mov [esp+WOffs],ecx mov ebp,[esp+HOffs] @Loop: movzx ebx,[esi+ecx*4].TRgbQuad.rgbReserved // S.Reserved test ebx,ebx jz @Next // Blue movzx eax,[esi+ecx*4].TRgbQuad.rgbBlue // S.Blue movzx edx,[edi+ecx*4].TRgbQuad.rgbBlue // D.Blue sub eax,edx // S.Blue-D.Blue imul ebx // (S.Blue-D.Blue)*S.Reserved add [edi+ecx*4].TRgbQuad.rgbBlue,ah // Green movzx eax,[esi+ecx*4].TRgbQuad.rgbGreen // S.Green movzx edx,[edi+ecx*4].TRgbQuad.rgbGreen // D.Green sub eax,edx // S.Green-D.Green imul ebx // (S.Green-D.Green)*S.Reserved add [edi+ecx*4].TRgbQuad.rgbGreen,ah // Red movzx eax,[esi+ecx*4].TRgbQuad.rgbRed // S.Red movzx edx,[edi+ecx*4].TRgbQuad.rgbRed // D.Red sub eax,edx // S.Red-D.Red imul ebx // (S.Red-D.Red)*S.Reserved add [edi+ecx*4].TRgbQuad.rgbRed,ah // Reserved mov [edi+ecx*4].TRgbQuad.rgbReserved,$FF @Next: add ecx,1 jl @Loop // Nächste Zeile add esi,[esp+OOffs] add edi,[esp+UOffs] mov ecx,[esp+WOffs] sub ebp,1 jnz @Loop @End: popad end; |
AW: Geht das noch schneller? - Bitmap-Verrechnung
Um das jetzt noch zu vervollständigen: Jetzt funktioniert auch Deine Lösung mit ca. 32 MS recht schnell und richtig.:thumb:
Wenn man die Graphics32 also nicht verwenden möchte, wäre Deine Lösung auch noch eine Variante. OK, mit XE2 kannst Du das Demo nicht kompilieren, da ja dort noch nicht die TParallel-Library zur Verfügung stand. Wenn Du aber die "System.Threading" Unit rausnimmst und "Draw32BitToBitmappara" auskommentierst sollte es gehen. |
AW: Geht das noch schneller? - Bitmap-Verrechnung
Ich bitte um Entschuldigung, wenn ich eine Frage habe, die nicht ganz zum Thread passt, aber:
Frage: Gibt es eine Möglichkeit, ein Bitmap mit geringer Auflösung (72dpi), das sich beim vergrößern total verpixelt, irgendwie so zu schärfen, dass die Details sichtbar werden? also in Krimisendungen habe ich das schon gesehen, dass dort Aufnahmen vergrößert werden, dann verpixelt sind, dann mit einem Programm dennoch geschärft werden. Mir geht es dabei nicht, um irgendwelche verpixelten Gesichter zu erkennen, sondern um andere Objekte. Enthält also eine kleine Grafik genug Infos, um die beim Vergrößern entstehenden Quadrate mit einem Algorythmus so zu bearbeiten, dass daraus ein größeres scharfes Bild wird? Enthalten die Blöcke oder Quadrate überhaupt genug Farbinfos dafür? Oder geht da wohl nur was mit Vectoren...? |
AW: Geht das noch schneller? - Bitmap-Verrechnung
Dann eröffne doch bitte einen neuen Thread für eine andere Frage.
Dann musst du doch nicht den Thread vom armen Harry durcheinander bringen. :( Kurze Antwort: Nein, das geht nicht zufriedenstellend automatisch. Reine Fiktion. |
AW: Geht das noch schneller? - Bitmap-Verrechnung
Nach flüchtigem Verfolgen der Diskussion meine ich:
Es geht hier, wie schon anklang, um Alphablending. Da gab es doch 2005 das Thema Alphablending mit MMX / SSE Befehle Aber zur jetzigen Diskussion Wenn man anstatt 255 durch 256 per Shift dividiert, dann geht das nur bei nichnegativem Nenner. Für den Datentyp Int32 kann man den Trick mit der magischen Zahl $8081 zur Division durch 255 verwenden. const Magic: UInt16 = $8081; var n: Integer; Dann ist für -Sqr(255) <= n<=Sqr(255) ( n * Magic) div (1 shl 23) = n div 255 Der Compiler erzeugt für den ersten Ausdruck einen arithmetische Rechtsshift um 23. Müsste mal mit RDTSC timen. Manfred |
AW: Geht das noch schneller? - Bitmap-Verrechnung
nur mit einem Auge das hier verfolgt, aber ist folgender Blog nicht genau das Thema:
![]() Die haben hier ein VCL Beispiel und hinweise für die Firemonkey Umsetzung |
AW: Geht das noch schneller? - Bitmap-Verrechnung
Zitat:
|
AW: Geht das noch schneller? - Bitmap-Verrechnung
Man muss ja nicht gleich TParallel mit Canvas.Pixel verbinden. Vielleicht muss man auch manuell skalieren, d.h. durch Ausprobieren herausfinden, wo der break even zwischen Bildgröße und Anzahl der Threads ist.
|
AW: Geht das noch schneller? - Bitmap-Verrechnung
Ein Versuch in Vorbereitung einer MMX-Version
Delphi-Quellcode:
procedure Draw32BitToBitmapPreMMX(const BitOben: TBitmap; BitUnten: TBitmap);
const Magic: UInt16 = $8081; var W, x, y: Integer; Stride, ORes: Integer; RowO, RowU, RGBA_Oben, RGBA_Unten: ^TRGBQuad; begin RowU := BitUnten.ScanLine[0]; RowO := BitOben.ScanLine[0]; W := BitUnten.Width; Stride := 4 * W; for y := 0 to BitUnten.Height - 1 do begin RGBA_Unten := RowU; RGBA_Oben := RowO; for x := 0 to W - 1 do begin ORes := RGBA_Oben^.rgbReserved; with RGBA_Unten^ do begin rgbBlue := (ORes * (RGBA_Oben^.rgbBlue - rgbBlue)) * Magic div (1 shl 23) + rgbBlue; rgbGreen := (ORes * (RGBA_Oben^.rgbGreen - rgbGreen)) * Magic div (1 shl 23) + rgbGreen; rgbRed := (ORes * (RGBA_Oben^.rgbRed - rgbRed)) * Magic div (1 shl 23) + rgbRed; rgbReserved := 255; end; Inc(RGBA_Unten); Inc(RGBA_Oben); end; Dec(Cardinal(RowU), Stride); Dec(Cardinal(RowO), Stride); end; end; |
AW: Geht das noch schneller? - Bitmap-Verrechnung
Hier mein letztes Angebot
Delphi-Quellcode:
QUOTE=Harry Stahl;1281742]
unit UAlphaSSE;
{ SSE-Version von Harry Stahls procedure Draw32BitToBitmap(const BitOben: TBitmap; BitUnten: TBitmap); } interface uses Winapi.Windows, Vcl.Graphics; procedure Draw32BitToBitmapSSE(const BitOben: TBitmap; BitUnten: TBitmap); implementation procedure Draw32BitToBitmapSSE(const BitOben: TBitmap; BitUnten: TBitmap); const // bbggrr RGBFF: array[0..1] of UInt64 = ($FF000000, 0); // src bytes ......01......00 ......03......02 UMsk: array[0..1] of UInt64 = ($8080800180808000, $8080800380808002); // res bytes .......... 8 4 0 ................ PMsk: array[0..1] of UInt64 = ($8080808080080400, $8080808080808080); C255: array[0..3] of Single = (1/255, 1/255, 1/255, 0); var BmpO, BmpU: PRGBQuad; N: Integer; begin N := BitOben.Height; BmpO := BitOben.ScanLine[N - 1]; BmpU := BitUnten.ScanLine[N - 1]; N := N * BitOben.Width - 1; // size of bitmap - 1 asm PUSH EBX MOV EAX, BmpO MOV EDX, BmpU MOV ECX, N // XMM7 free LDDQU XMM6, UMsk LDDQU XMM5, PMsk LDDQU XMM4, C255 LDDQU XMM3, RGBFF {$IFOPT O+} DB $66,$90 // 2-Byte-NOP {$ELSE} DB $66,$0F,$1F,$44,0,0 // 6-Byte-NOP {$ENDIF} @Loop: MOVD XMM0, [EAX+4*ECX]// XMM0 = | 0 |α|B|G|R PEXTRW EBX, XMM0, 1 // EBX = α | B SHR EBX, 8 // EBX = 0 | α JZ @LoopEnd // test α ≡ RGBA_O.rgbReserved = 0 ? PSHUFB XMM0, XMM6 // unpack to Int32 CVTDQ2PS XMM0, XMM0 // convert RGB_O to single FP // SHUFPS XMM1, XMM0, $FF // !!! useless result MOVAPD XMM1, XMM0 // copy RGB_O (necessary !) SHUFPS XMM1, XMM1, $FF // XMM1 = α | α | α | α MULPS XMM1, XMM4 // XMM1 = 0 | α/255 | α/255 | α/255 MOVD XMM2,[EDX+4*ECX] // XMM2 = | 0 |α|B|G|R PSHUFB XMM2, XMM6 // unpack to Int32 CVTDQ2PS XMM2, XMM2 // convert RGB_U to single FP SUBPS XMM0, XMM2 // RGB_O - RGB_U MULPS XMM0, XMM1 // α * (RGB_O - RGB_U) / 255 ADDPS XMM0, XMM2 // α * (RGB_O - RGB_U) / 255 + RGB_U CVTPS2DQ XMM0, XMM0 // convert FP to Int32 with rounding PSHUFB XMM0, XMM5 // pack into TRGBQuad POR XMM0, XMM3 // RGB_U.rgbReserved = $FF MOVD [EDX+4*ECX],XMM0 // restore RGB_U @LoopEnd: SUB ECX, 1 JNS @Loop POP EBX end; end; end. Zitat:
Mit anonymen Threads habe ich hier nichts machen können. Sie laufen schön langsam nacheinander auf dem selben Prozessorkern. Könnte vor Wut das CPU-Gatget pulversisieren Manfred |
AW: Geht das noch schneller? - Bitmap-Verrechnung
|
AW: Geht das noch schneller? - Bitmap-Verrechnung
Bitte antworte in vollständigen Sätzen, also: Subjekt, Prädikat, Objekt. Es ist ein wenig dadaistisch, was Du da von Dir gibst und von einfachen Menschen wie mir so nicht zu verstehen.
|
AW: Geht das noch schneller? - Bitmap-Verrechnung
Soll das nur übereinander Angezeigt werden?
Da hätte ich auch ein Beispiel mit GDI+ da rechnet das ja die GPU zusammen? |
AW: Geht das noch schneller? - Bitmap-Verrechnung
Liste der Anhänge anzeigen (Anzahl: 1)
Hier ein Beispiel mit GDI+
Die ganze Unit ist im Anhang incl. drehen und interpolation einfach in ein Package einbinden und ausprobieren Die GDI+ Units sind im XE4 bei mir schon enthalten Einen Geschwindigkeitsvergleich habe ich noch nicht gemacht Mit Transparenten PNG´s klappt das wohl, aber 32Bit BMP´s nicht Kann ich noch Optimieren zb. Ram sparen, wenn ich den Stream Plattmache funktionieren JPG´s nicht mehr
Delphi-Quellcode:
uses GDIPOBJ, GDIPAPI;
... TTestImage = class(TGraphicControl) private { Private declarations } fImageA1: TGPImage; fImageB1: TPicture; fStream1: TMemoryStream; fImageA2: TGPImage; fImageB2: TPicture; fStream2: TMemoryStream; ... procedure TTestImage.Paint; var Graphics: TGPGraphics; begin Graphics := TGPGraphics.Create(Canvas.Handle); try Graphics.DrawImage(fImageA1, 0, 0, Width, Height); Graphics.DrawImage(fImageA2, 0, 0, Width, Height); finally Graphics.Free; end; end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 07:01 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz