MiniCL - Berechnungen auf GPU in einer Zeile (kein OpenCL)

  • Moin.


    Ich möchte mal ein Mini-Projekt von mir vorstellen: MiniCL.


    Was?


    Wie bereits bekannt, hat Andy letztes Jahr (oder war es länger her...?) Header für OpenCL in AutoIt geschrieben (und das dann noch mit OpenGL verheiratet). Vorteil war, dass man jetzt alles was parallel läuft auf GPU (GPGPU) oder auf der CPU laufen lassen konnte. Leider müssen dafür nicht nur verschiedene SDKs für verschiedene Hersteller geladen und mitgeliefert werden, OpenCL ist auch nicht gerade die kompatibelste API.


    Ich möchte das ändern und das Berechnen auf GPU einfach gestalten. Ich schreibe deswegen eine DLL dafür, welche am Ende das einzige sein soll, was man mitliefern muss. Hier ist ein kleines Featureset:


    • Komplett self-contained (GLEW usw. sind alle direkt reinkompiliert).
    • Kernel werden in OpenGL GLSL geschrieben
    • Structs mit Daten können aus AutoIt einfach übergeben werden und die Ergebnisse werden destruktiv dort hineingeschrieben
    • Kompatibel mit allen OpenGL-fähigen Grafikkarten
    • MiniCL übernimmt OpenGL Initialisierung, Nutzer bekommt davon nichts mit
    • (geplant) Es können beliebig viele Kernel auf einmal übergeben werden, genauso mehrere Input-Structs, um den Overhead zu minimieren (möglichst viel auf GPU rechnen, nur Setup auf CPU)

    Das hier ist z.B. ein funktionierender Testcode. Es wird ein Array mit 6 floats erzeugt, an MiniCL übergeben, manipuliert:



    ; Daten erstellen


    $tInputData = DllStructCreate("float Value[" & 3 * 2 & "];")


    $tInputData.Value(1) = 0
    $tInputData.Value(2) = 0.1
    $tInputData.Value(3) = 1
    $tInputData.Value(4) = 1.1
    $tInputData.Value(5) = 2
    $tInputData.Value(6) = 2.1


    ; Daten auf GPU kopieren, Kernel ausführen


    ; Entspricht: Value(n) = Value(n)^2 + 0.2


    ConsoleWrite(@LF & "+> " & DllCall("main.dll", _
    "int:cdecl", "ExecuteMiniCL", _
    "str", "void main(void){ float c = texture2D(SRC, location).r; gl_FragColor = c * c + 0.2; }", _
    "ptr", DllStructGetPtr($tInputData)) _
    [0] & @LF)


    Der Output ist dann folgender:


    Code
    --> Press Ctrl+Alt+Break to Restart or Ctrl+Break to Stop
    +> [MiniCL] Kernel successfully executed. Output data:
    -> 0.20 0.21
    -> 1.20 1.41
    -> 4.20 4.61
    +> [MiniCL] Kernel used: void main(void){ float c = texture2D(SRC, location).r; gl_FragColor = c * c + 0.2; }
    +>14:32:21 AutoIt3.exe ended.rc:0
    +>14:32:21 AutoIt3Wrapper Finished.


    Auf der GPU liegen Daten immer als 2D Matrix vor. Beim Übergeben an MiniCL konvertiert MiniCL den Array automatisch in eine Matrix.


    ToDo


    Bisher, wie man sieht, ist die Rückgabe noch nicht integriert. Das liegt an der katastrophalen Funktion glutWindow...(), welche AutoIt crasht, weil sie sich zu fein ist ein einem DLL-Thread zu laufen. freeglut.dll muss auch zur Zeit noch mitgeliefert werden. Ich plane aber das durch einen eigenen OpenCL context zu ersetzen (bisher taucht nämlich das eigentliche glut Fenster immer auf, was blöd aussieht :D ). Wenn das getan ist, muss wirklich nur noch MiniCL an sich mitgeliefert werden :)

  • Jetzt ist glut bzw. freeglut endlich aus dem Code verschwunden. Damit hat sich der Overhead von ~500 auf ~180 ms reduziert. Die Kernelzeit ist etwa ~30 µs. Somit ist MiniCL.dll die einzige DLL die geladen werden muss. Mit UPX ist die etwa noch 250KB groß.


    Problem: AutoIt crasht noch immer nach erfolgreicher "Rückgabe" der Daten...

  • Problem gelöst. Das Problem lag bei dem eigenen WndProc vom Fenster, welches MiniCL erzeugt. AutoIt will diesen Loop nicht und crasht. Lösung: Dummy-GUI in AutoIt erzeugen und hWnd nach MiniCL übergeben, damit dort dann OpenGL initialisiert wird. Die Proc wird von AutoIts GUI geklaut. ^^