Autor |
Beitrag |
Mathematiker
Beiträge: 2622
Erhaltene Danke: 1447
Win 7, 8.1, 10
Delphi 5, 7, 10.1
|
Verfasst: Do 30.07.15 23:41
Hallo,
user32 hat folgendes geschrieben : | Aha. Bitmap Optimierung. Hat mich jemand gerufen? ;]
Folgende Version ist um den Faktor 100 (Hundert) schneller. |
Ich bin ehrlich gesagt fasziniert. Wie geht denn so etwas? 100fach schneller.
Vielen, vielen Dank!
Ich habe es gerade getestet: Deine Lösung ermöglicht ja sogar in Echtzeit die waagerechte bzw. senkrechte Verschiebung des Mittelpunktes, d.h. die Kugel kann man drehen!
Darf ich dich für weitere Programme "anstellen"?
Beste Grüße
Mathematiker
_________________ Töten im Krieg ist nach meiner Auffassung um nichts besser als gewöhnlicher Mord. Albert Einstein
|
|
Horst_H
Beiträge: 1653
Erhaltene Danke: 243
WIN10,PuppyLinux
FreePascal,Lazarus
|
Verfasst: Fr 31.07.15 08:04
Hallo,
jau, das jede Zeile das Bild neu gezeichnet wird ist suboptimal...
Das es bei 960 Zeilen nur 100 mal schneller wird ist erstaunlicher , wieso ist mir das nicht aufgefallen?
Ich habe das Program unter wine laufen und habe access violation:
Gruß Horst
P.S:
Unter Win7 habe ich keine Fehler..
Ich habe keine Verbesserung gefunden, obwohl ich keine Unterschiede zwischen single und double habe ( Turbo Delphi ).es dauert bei mir 0.01265 Sekunden pro Bildberechnung.Die Ausgabe auf die Paintbox ist nicht drin.
Für wine/Lazarus musste ich ExtractFilePath nutzen, weil er sonst die Bilder nicht findet.Aber dabei hatte ich kein umgerechnetes Bild.Scanline will da nicht so recht.
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: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96:
| procedure TForm1.Button1Click(Sender: TObject); var bitmap,bitmap2,bitmapz:tbitmap; T1,T0 : TDatetime; rect:trect; P : PByteArray; p2: ^byte; p3,px: ^byte;
i,j,n,k,waagerecht,senkrecht,bmw:integer; xm,ym:integer; bbinv, xk,yk,q,xi,yi,sq:single;
procedure ladejpg(const FileName: String; Bild: TBitMap); var Jpeg: TJpegImage; begin Jpeg:=TJpegImage.Create; jpeg.LoadFromFile(filename); Bild.Assign(Jpeg); jpeg.free; end; begin
ladejpg(ExtractFilePath(application.ExeName)+combobox1.text+'.jpg',image1.Picture.Bitmap); application.ProcessMessages;
waagerecht:=bb; senkrecht:=bb;
bitmap2:=tbitmap.create; bitmap2.assign(image1.Picture.Bitmap); bitmap2.PixelFormat:=pf32bit;
bitmap:=tbitmap.Create; bitmap.width:=bb; bitmap.height:=bb; rect.left:=0; rect.Top:=0; rect.right:=bb; rect.Bottom:=bb; bitmap.canvas.copyrect(rect,bitmap2.Canvas,image1.clientrect); xm:=paintbox1.Width div 2; ym:=paintbox1.height div 2;
bitmapz:=tbitmap.Create; bmw :=paintbox1.Width; bitmapz.Width:= bmw; bitmapz.height:=paintbox1.height; bitmapz.PixelFormat:=pf32bit;
bitmapz.Canvas.Brush.Color:=clwhite; bitmapz.Canvas.Rectangle(-1,-1,961,961); bbinv := 1/bb; T0 := now; For n := 1 to runden do Begin P2 := BitMap.ScanLine[0]; P3 := bitmapz.ScanLine[0];
for i:=0 to bb-1 do begin yi:=(2*i-senkrecht)*bbinv; for j:=0 to bb-1 do begin xi:=(2*j-waagerecht)*bbinv; sq := xi*xi + yi*yi; if sq<1.0 then begin q:=480/(sq+1.0); px := p3; dword(px) := dword(px) -((trunc(yi*q)+ym)*bmw + trunc(xi*q)+xm)*4; pDword(px)^ := pDword(p2)^;
end; inc(p2,4); end; dec(p2, 8*bitmap.Width); end; End; T1 := now; paintbox1.Canvas.Draw(0,0,bitmapz);
bitmap.free; bitmap2.free; bitmapz.free; Label1.Caption := Format('%10.5f',[(T1-T0)/n*86400.0]); end; |
Einloggen, um Attachments anzusehen!
|
|
user32
Beiträge: 55
Erhaltene Danke: 5
|
Verfasst: Fr 31.07.15 18:40
Mathematiker hat folgendes geschrieben : | Hallo,
user32 hat folgendes geschrieben : | Aha. Bitmap Optimierung. Hat mich jemand gerufen? ;]
Folgende Version ist um den Faktor 100 (Hundert) schneller. |
Ich bin ehrlich gesagt fasziniert. Wie geht denn so etwas? 100fach schneller.
Vielen, vielen Dank!
Ich habe es gerade getestet: Deine Lösung ermöglicht ja sogar in Echtzeit die waagerechte bzw. senkrechte Verschiebung des Mittelpunktes, d.h. die Kugel kann man drehen!
Darf ich dich für weitere Programme "anstellen"?
Beste Grüße
Mathematiker |
Sicher, wenn ich helfen kann immer gerne
Wobei ich mich selbst noch als Optimierungs-Newbie sehe..
Joa, Canvas-Funktionen wie LineTo oder Pixels, sind sehr einfach und praktisch, aber bei Software Rendering kann man es echt vergessen.
Einzelnd aufgerufen okay, aber sobald eine Schleife dabei ist....
Horst_H hat folgendes geschrieben : | Hallo,
jau, das jede Zeile das Bild neu gezeichnet wird ist suboptimal...
Das es bei 960 Zeilen nur 100 mal schneller wird ist erstaunlicher , wieso ist mir das nicht aufgefallen?
Ich habe das Program unter wine laufen und habe access violation:
[Bild: capture29363]
Gruß Horst
P.S:
Unter Win7 habe ich keine Fehler..
Ich habe keine Verbesserung gefunden, obwohl ich keine Unterschiede zwischen single und double habe ( Turbo Delphi ).es dauert bei mir 0.01265 Sekunden pro Bildberechnung.Die Ausgabe auf die Paintbox ist nicht drin.
Für wine/Lazarus musste ich ExtractFilePath nutzen, weil er sonst die Bilder nicht findet.Aber dabei hatte ich kein umgerechnetes Bild.Scanline will da nicht so recht.
|
Du meinst Lazarus kennt nicht Single/Double? Oder nur keinen Geschwindigkeitsunterschied gemessen?
Ich vermute das kommt wohl auf den Compiler an.
Bei mir läuft das ursprüngliche Programm, alleine durch Umstellen auf Single, ca 33% schneller.
Deswegen hab ich auch Sachen wie sq() gegen x*x getauscht, weil diese Funktionen meistens mit Extended rechnen und zudem ja noch zusätzlich eine externe Funktion aufgerufen wird.
Würde mich mal interessieren, ob wenn du die FPU manuell auf 32-bit setzt, das immer noch gleich schnell ist.
|
|
Horst_H
Beiträge: 1653
Erhaltene Danke: 243
WIN10,PuppyLinux
FreePascal,Lazarus
|
Verfasst: Fr 31.07.15 23:52
Hallo,
natürlich kennt Lazarus wie Turbo Delphi single und double.
Es ändert das Tempo bei mir nicht.
Das ich kein Bild unter Linux/wine bekomme liegt einfach nur am geänderten Aufbau der Bitmaps.
Unter Windows ist die oberste Zeile 0 im hohen Speicherbereich und die anderen kommen im Speicher davor.
Man wandert von Zeile zu Zeile zu kleineren Speicheradressen.
Unter Linux ist es genau andersherum.
Zeile 0 ist oben auf dem Bildschirm und die niedrigste Postion im Speicher und man wandert im Speicher zu höheren Adressen.
Deshalb stimmt die Bestimmung von px nicht mehr, weil die Zeilen jetzt falsch berechnet werden zudem von der falschen Startposition.Das gibt nur deshalb nicht immer eine Zugriffsverletzung, weil das Bitmap das davor erzeugt ist auch oft genau davor liegt und völlig überschrieben wird, was keiner sieht, es wird ja nicht zur Anzeige gebracht.
Gruß Horst
|
|
user32
Beiträge: 55
Erhaltene Danke: 5
|
Verfasst: Sa 01.08.15 04:05
Moderiert von Narses: Komplettzitat des vorigen Beitrags entfernt.
Ja, stimmt. Ich wusste garnicht, dass es bei Linux anders ist. Naja, man könnte sagen Linux hat es richtig gemacht und Microsoft falsch
Aber wenn du die Pointer Adressen umstellst, sollte es bei Linux ja dann auch gehen.
|
|
SMO
Beiträge: 120
Erhaltene Danke: 18
D2005 Personal
|
Verfasst: So 02.08.15 01:45
Horst_H hat folgendes geschrieben : | bekomme liegt einfach nur am geänderten Aufbau der Bitmaps.
Unter Windows ist die oberste Zeile 0 im hohen Speicherbereich und die anderen kommen im Speicher davor.
Man wandert von Zeile zu Zeile zu kleineren Speicheradressen.
Unter Linux ist es genau andersherum. |
Stimmt, unter Windows sind Bitmaps gewöhnlich "bottom-up". Aber man kann auch "top-down" Bitmaps anlegen, dafür muss man einfach eine negative Höhe angeben. Delphis TBitmap Kapselung unterstützt das allerdings nicht, d.h. man müsste die Windows-API direkt benutzen.
Wenn man ordentlich programmiert, dann ist der Speicheraufbau von Bitmaps eigentlich irrelevant. Entweder ruft man für jede Zeile TBitmap.Scanline auf um den passenden Pointer zu bekommen, oder man ermittelt initial den "Pitch" (Schrittweite von einer Scanline zur nächsten, im Fall von Windows eben ein negativer Wert) und addiert ihn nach jeder Zeile auf den aktuellen Scanline-Pointer.
|
|
|