Übersetzung nach FreeBasic

  • Ich möchte folgende Funktion nach FreeBasic übersetzen, aber ich bekomme eine Speicherschutzverletzung.


    Die Struct wird über eine andere Funktion erstellt und ist dynamisch.

    AutoIt
    Local Const $iCountX = Int($aDim[0] / $iStep), $iCountY = Int($aDim[1] / $iStep)
    	Local Const $tagData = "struct;float x[" & $iCountX & "];float y[" & $iCountX & "];float z[" & $iCountX & "];float fX[" & $iCountX & "];float fY[" & $iCountX & "];float fZ[" & $iCountX & "];uint pen[" & $iCountX & "];endstruct"


    Hier der fehlerhafter FreeBasic Code:


    Im Prinzip will ich die Schleife per freeBasic beschleunigen!


    Meine Lösung siehe Post#20. Vielen Dank an @eukalyptus für die Hilfestellungen! :thumbup:


    Vielen Dank.

  • Sehe ich das richtig, dass das eine Zentralprojektion werden soll mit einem Augpunkt welcher nicht auf der Z-Achse liegt?
    Wenn dann wäre es vielleicht angebracht erst einmal auf algorithmischer Ebene zu optimieren.
    So wie ich das sehe führst du die Parameterberechnung dabei für jeden Punkt erneut aus.
    Sicherlich wäre es aber möglich die Verschiebung des Augpunktes und der Zentralprojektion in eine Transformationsmatrix zu gießen welche für alle Punkte Gültigkeit besitzt. "Direkte Lineare Transformation" sollte der entsprechende Suchbegriff dazu sein (auch wenn diese meist eher andersherum angewandt wird - also aus Passpunkten die Transformationsparameter zu bestimmen).
    Heißt also die Matrix nur einmal berechnen und dann auf alle Punkte anwenden.

    Ist zwar nicht deine konkrete Fragestellung und ich selbst müsste dafür auch erst einmal bisschen Zeit aufwenden aber ich denke damit könntest du schon ne Menge rausholen.

  • Vielen Dank Aspirin Junkie, aber meine letzte Mathe Vorlesung liegt im letzten Jahrtausend zurück, aber ich versuche die DLT zu verstehen und entsprechend anzuwenden.

    Nichtsdestotrotz stößt AutoIt bei solchen Operationen schnell an seine Grenzen, sodass das Einsetzen von 3rd Party Code, z.B. Assembler oder ext. DLLs sich i.d.R. nicht vermeiden lässt, wenn man die FPS erhöhen will.

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Soweit ich weiß kann man Abbildungsmatrizen miteinander Multiplizieren und die daraus entstehende Matrix auf die Punkte anwenden, anstatt die Matrizen nacheinander anzuwenden.

    In deinem Fall müsste man dann eine Translationsmatrix, eine Rotationsmatrix und eine Zentralprojektionsmatrix zusammenfassen.

    Eine Multiplikation einer Matrix mit einem Vektor lässt sich auch in ASM einfach handhaben (Ich wette es gibt genau für diesen Fall irgendeinen speziellen SSE Befehl der das in einem Takt macht). Wenn die Matrix steht sollte das Anwenden also recht flott gehen.

    Villeicht hilft die das hier Klick Mich

    M

  • Das (übliche) Problem ist nicht die "Optimierung" des Algorithmus (wobei ich das immer zuerst machen würde) sondern die Ausführungsgeschwindigkeit von AutoIt, in diesem Fall kommt noch die "Langsamkeit" von GDI+ dazu...
    Ich hatte die Berechnung der 3D in 2D-Koordinaten spaßeshalber bereits in ASM (unter Verwendung der "sehr langsamen" FPU-Befehle) durchgeführt. Um mal Verhältnisse zu beschreiben, die reine Transformation bzw. Berechnung von mehreren tausend Kanten erfolgt für das Bild in 0,1ms, die "Darstellung" eines Frames über GDI+ dauerte 10-20ms, also schlapper Faktor 100 für das Verhältnis (langsame) Berechnung zu Darstellung!
    Es bringt also in diesem Fall nichts, die ohnehin schon sehr schnelle Berechnung zu beschleunigen!

    Was sehr wohl etwas bringt, sind die GDI+-Befehle rauszulassen, die 3D-2D Transformation auf die Bildpunkte zu übertragen und die so entstandene "Grafik" als nackte Bitmap per GDI (ohne plus) anzuzeigen....

    Dazu gehört aber, die Berechnung für alle BxH Bildpunkte per wie-auch-immer-DLLCall abzuwickeln! Für einen einzelnen Punkt eine 2D3D-Transformation auszuführen (egal wie schnell) und dann in AutoIt diese für die gesamte Grafik aufzurufen ist sogar kontraproduktiv! Da ist selbst das "langsame" AutoIt schneller als der Overhead eines millionenfach aufgerufenen DLLCall() !

  • Es bringt also in diesem Fall nichts, die ohnehin schon sehr schnelle Berechnung zu beschleunigen!

    Doch, und wie es das bringt! AutoIt ist nicht gleich ASM, ich gehe mal stark davon aus, dass der Sinus & Cosinus noch mehr Takte verschwenden, als sie es direkt implementiert auf Prozessorebene tun würden.
    Gehen wir mal davon aus, dass eine Trigonometrische Funktion 5 Takte, eine Multiplikation dagegen 1 Takt (reine Rechenzeit, Daten laden & speichern mal ausgelassen) benötigt, dann würden wir schon alleine mit den 3 Matrizen pro "Grundberechnung" schon mal 24 Millisekunden sparen. Im Verhältnis dauert das also 4 Mal so lang, wie eine normale Multiplikation.
    Gehen wir nun (wenn das nicht AutoIt wäre) davon aus, dass wir unsere Matrizen ferner noch im Cache haben, dann sind wir von der Zeit her absolut unschlaggbar. Diese Sinus & Cosinus Methode lässt den Code nämlich zu 100% Cachefrei, was also zuzüglich noch mehr Takte verschwendet, die wir bereits effektiv nutzen könnten.
    Anbei noch kurz zu der Berechnung in unter 0.1ms - Natürlich schaffst du 1000 Kanten in <0.1ms, wenn wir davon ausgehen dass wir 20 Takte pro Kante haben, dann haben wir bei einem 2 GHz Prozessor 0.00002 Sekunden Rechenzeit für das Ganze (20*1000)/(10^9)

    Es gibt sehr viele Leute, die glauben. Aber aus Aberglauben.
    - Blaise Pascal

  • Ich wollte eigentlich erst mal wissen, was FreeBasic bei gleichen Bedingungen schafft, bevor ich mich sukzessiv an die Optimierung mache, z.B. über Direkte Lineare Transformation.

    Andy: Dass GDI+ Funktionsaufrufe nicht die Schnellsten sind, ist klar, aber unter den gleichen Bedingungen ist FreeBasic auf meiner Kiste ca. 23x schneller.

    Ein klassisches Beispiel im Anhang: zufällige Farben in eine Bitmap schreiben, die 400x300 groß (klein) ist.


    GDI+ Test 01.au3:


    GDI+ Test 01.bas:


    Primär geht es mir erst mal um die Implementierung in FreeBasic!

  • @UEZ dann würdest du dir aber doppelt Arbeit machen. Wenn du den Algorithmus gleich "optimal" entwirfst, dann musst du ja nur den portieren. Wenn du jetzt aber sowohl A als auch B zwei Mal schreibst, dann schreibst du A einmal zu viel.

    Es gibt sehr viele Leute, die glauben. Aber aus Aberglauben.
    - Blaise Pascal

  • @UEZ dann würdest du dir aber doppelt Arbeit machen. Wenn du den Algorithmus gleich "optimal" entwirfst, dann musst du ja nur den portieren. Wenn du jetzt aber sowohl A als auch B zwei Mal schreibst, dann schreibst du A einmal zu viel.

    Das macht erst mal nichts, denn, wie gesagt, geht es mir primär um FreeBasic, dann um die Optimierung. Dass es zu doppelten Arbeiten dadurch kommt, ist mir erst mal egal.

    ^^

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Doch, und wie es das bringt!

    Wenn du meinst...
    Ich jedenfalls habe eine reale Anwendung geprofiled, und da waren die Anteile von Berechnung + Darstellung ca. 1+ 100 -> FPS ca. 50. Und man muss kein exzellenter Mathematiker sein um herauszufinden, dass bei einer Beschleunigung der Berechnung um Faktor 1000 die Darstellung die gleiche Zeit wie vorher dauert. Ergo 0,001+100 -> 50FPS.

    Bei einer Optimierung fängt man generell bei den "großen Brocken" an, und nicht bei irgendeinem Gedöns, welches letztendlich auf das Ergebnis nur minimale Auswirkungen hat!

    Übrigens habe ich folgende Mathematische Umformung benutzt, um die Sin() und Cos()-Berechnung komplett aus der Schleife draussen zu lassen. In der eigentlichen Schleife werden statt der trigonometrischen Funktionen nur noch Additionen und Multiplikationen verwendet, in den Prozessoren gibt es dafür den PMADDWD-Befehl, welcher 4 Multiplikationen und 2 Additionen in EINEM Takt durchführen kann!
    Übrigens gibt es alle diese "Beschleuniger"-Befehle als Intrinsics für C(++)-Compiler, für diejenigen, die wirklich ans Limit gehen wollen (müssen). Dazu ist zunächst richtiges Profiling nötig, die neueren (INTEL-) Compiler bringen dafür höchst eindrucksvolle Werkzeuge mit, da kann man nur staunen...mich würde brennend interessieren, wie viele "Programmierer" ihren Code damit tatsächlich analysieren...

  • Um die dynamische Struct in FreeBasic anzusprechen, kannst du mit Pointern arbeiten:

    Hier zwei Möglichkeiten:

  • @eukalyptus: Vielen Dank. :thumbup:

    Wie zu erwarten hat Translate3Dto2D in FreeBasic natürlich nichts gebracht, aber darum ging es mir ehe nicht, sondern FB zu lernen.

    Nächster Schritt ist nun die Schleifen in Freebasic zu implementieren:

    Nun muss ich eine Array nach FreeBasic übergeben und dort die Schleife ausführen. Mal sehen, wie schneller dies wird, falls ich FB dazu bekomme, dies zu tun, was ich will.

    Geht das überhaupt ein Array (keine Struct!) zu übergeben?

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Entweder du packst alles in eine Struct "float X[" & iCntX * iCntY & "]; float Y[" & iCntX * iCntY & "];

    oder du machst es auf diese Weise:

  • Kackt mit einer Speicherschutzverletzung ab:

    AutoIt:


    FreeBasic:


    Scheint an GdipDrawLine(hCanvas, hPen, pfX[c - 1], pfY[c - 1], pfX[c], pfY[c]) zu liegen!?


    @eukalyptus: kannst du den Fehler sehen?

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Bitte sehr. :D

    Es scheint, dass die Pointer nicht stimmen!

    Edit:

    Dies hier kackt nicht ab, aber Bildschirm bleibt dunkel. :(

  • Das hier funzt: