Hi zusammen,
vor gut einem Jahr habe ich OpenCL mit OpenGL kombiniert.
Mit OpenCL werden gut parallelisierbare Berechnungen auf der Grafikkarte oder einem Grafikprozessor oder einer CPU ausgeführt. Diese Berechnungen erfolgen aufgrund der Leistungsfähigkeit der modernen Grafik-Prozessoren wesentlich schneller als auf einer Hightech-CPU. Der "Flaschenhals" ist idR. der Transport der Daten aus dem RAM in den Speicher der Grafikkarte und wieder zurück ins RAM.
Bei grafischen Berechnungen bietet es sich also an, die Daten, die ja schon fertig berechnet im Speicher der Grafikkarte stehen, von dort direkt anzuzeigen. Und hier kommt OpenGL ins Spiel!
Ich verwende die mit OpenCL berechneten "Bilder" einfach als OpenGL-Textur, und lasse diese dann im OpenGL-Kontext darstellen. Die berechneten Daten verbleiben also im Speicher der Grafikkarte!
Das beschleunigt die Darstellung gegenüber dem Verfahren "per GDI blitten" (also Daten aus der Graka in den RAM schreiben und das dann wieder per GDI auf die Graka blitten) um den Faktor 3-5!
Um das Ganze auch handlebar zu machen, habe ich versucht, die Funktionen so weit wie möglich zu wrappern, damit sich der Anwender nicht mit den OpenCL- und GL-Interna auseinandersetzen muss. Die entsprechenden (meist C++) Beispiele in den OpenCL/GL-SDK´s sind (jedenfalls für mich) extrem unübersichtlich, weiß der Teufel, wieso da keiner auf die Idee kommt, hunderte ewig gleich ablaufende Funktionsschritte in eine Handvoll gewrapperte Funktionen zu schreiben....
Bei den Beispielen weden die aus den ASM- und OpenCL-Threads bekannten Scriptbeispiele Tunnelflug und Flug durch die Mandelbrotmenge einmal im Fenster komplett und dann als Projektion auf die Oberflächen von mehreren drehenden Würfeln verwendet. Selbst auf meinem Billigrechner mit Low-Lvl-GPU läuft der Tunnelflug in einem 768x768 Fenster mit sehr knapp unter 1000FPS , die Projektion des Fluges durch die Mandelbrotmenge auf den Oberflächen der rotierenden Würfel mit ca. 120FPS.
Fürs OpenGL habe ich die Funktionen von minx´ens UDF verwendet und ggf. angepasst.
Die OpenCL-Funktionen kennt der eine oder andere vielleicht schon aus den entsprechenden Threads.
Verfahrensweg ist folgender:
- OpenGL-Fenster und -Textur erstellen
- Mit OpenCL die Textur mit Bilddaten (Pixeln) füllen
- Textur im OpenGL-Fenster darstellen.
Spoiler anzeigen
#region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_usex64=n
#endregion ;**** Directives created by AutoIt3Wrapper_GUI ****
#region ;**** Directives created by AutoIt3Wrapper_GUI ****
#endregion ;**** Directives created by AutoIt3Wrapper_GUI ****
#include "..\Includes\opengl.au3"
#include <opencl_easy.au3>
#include <GUIConstantsEx.au3>
#include <WinAPI.au3>
#include <GDIConstants.au3>
#include <Misc.au3>
#include <CLGL_easy.au3>
;INFOS!!!
;erst textur in openGL erstellen und binden, dann erst CL-context erstellen
;programmspezifisch...
$CL_DEBUGFLAG = 1 ;1 debug aus
Global $width = 256 * 3 ;breite und höhe des Fensters
Global $height = 256 * 3
Local $iAlpha = 0.00 ; Rotationswinkel um den Würfel zu drehen.
Global $textur_width = $width, $textur_height = $height ;texturmaße = Fenstermaße
[/autoit] [autoit][/autoit] [autoit]Local $step = 1.02 ;das ist die Schrittweite, um die der Tunnelflug ein Frame weiter gezeichnet wird
Local $steps = 0 ;Beginn des Fluges...
$KernelSource = FileRead("Tunnelflug.cl") ;kernelsource aus datei laden
ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $KernelSource = ' & $KernelSource & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
;OpenGL und extensions initialisieren
glInit()
;gluInit()
glfwInit()
;Fenster einrichten
glfwOpenWindowHint($GLFW_WINDOW_NO_RESIZE, 1) ; Resize nicht möglich
glfwOpenWindow($width, $height, 8, 8, 8, 0, 8, 0, $GLFW_WINDOW) ; Fenster öffnen
glfwSetWindowTitle("tunnelflug ") ; Titel setzen
glMatrixMode($GL_PROJECTION) ; Projektionseinstellungen
;gluPerspective(14, $width / $height, 5, 40) ; Perspektive
glOrtho(0, $width, 0, $height, 0, 128)
glViewport(0, 0, $width, $height) ; Viewport
glMatrixMode($GL_MODELVIEW) ; Betrachtungsmodus
;GLCL context erstellen und an hdc (window) binden
setGLCLcontext() ;aktuellen gl-context an dc (window) binden
;leere textur erstellen mit höhe und breite
Local $textur1 = createGLCLtexturebuffer($textur_width, $textur_height)
;textur bereitstellen
glEnable($GL_TEXTURE_2D) ; aktuelle Textur einschalten
;glEnable($GL_DEPTH_TEST) ;tiefentest bei 3d, unbedingt beim drehenden würfel mal auskommentieren^^
setGLCLautokernel() ;CL-equipment initialisieren, kernel kompilieren usw
[/autoit] [autoit][/autoit] [autoit];bevor GL auf die Buffer zugreift, MUSS CL der Zugriff entzogen werden!!!
clFinish($command_queue)
;debugflag ausschalten 1=einschalten ;erzeugt debugausgabe in der console
$CL_DEBUGFLAG = 0 ;Debug-Ausgabe ausschalten, um Geschwindigkeit zu erhöhen
glClear($GL_COLOR_BUFFER_BIT + $GL_DEPTH_BUFFER_BIT) ;Fenster clear
glLoadIdentity() ;Ersetzt die aktuelle Matrix durch die Einheitsmatrix
;gldisable($GL_CULL_FACE)
;
glTranslatef($width / 2, $height / 2, 0)
AdlibRegister("fps", 1000) ;1x pro sekunde die FPS darstellen
_CL_SetArg(0, "ptr*", $writetoimage) ;erstes argument für den kernel ist das IMG
;hauptschleife
While glfwGetWindowParam($GLFW_OPENED) And Not glfwGetKey($GLFW_KEY_ESC);
; Sleep(10)
glFlush() ;GL erlaubt CL den Zugriff auf die Buffer
;Kernel Parameter
$steps += $step
_CL_SetArg(1, "float*", $steps) ;...und an kernel übergeben
[/autoit] [autoit][/autoit] [autoit][/autoit] [autoit];ACHTUNG, da SIMD-kernel, nur 1/4 der daten benötigt!!! s. $globalDS !!!!
executeCLkernel() ;Opencl-kernel ausführen, berechnet die Textur"pixel"
;glClear($GL_COLOR_BUFFER_BIT + $GL_DEPTH_BUFFER_BIT) ;
glBindTexture($GL_TEXTURE_2D, $textur1) ;
glBegin($GL_QUADS) ;
glTexCoord2f(0, 1) ;
glVertex2f(-$width / 2, -$height / 2) ;
glTexCoord2f(1, 1) ;
glVertex2f(+$width / 2, -$height / 2) ;
glTexCoord2f(1, 0) ;
glVertex2f(+$width / 2, +$height / 2) ;
glTexCoord2f(0, 0) ;
glVertex2f(-$width / 2, +$height / 2) ;
glEnd() ;
glFlush()
glfwSwapBuffers() ; Buffer tauschen.
$fps += 1 ;FPS FTW :o)
WEnd
[/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]; Aufräumen:
glDeleteTextures(1, $textur1)
glfwTerminate()
glTerminate()
;**********************Ende*********************
[/autoit]Ich habe die von mir verwendeten OpenGL-DLL´s und deren Erweiterungen mitgegeben, wahrscheinlich kann man auf diese verzichten, wenn OpenGL und CL auf dem Rechner installiert sind.
autoit.de/wcf/attachment/20862/ bspw. in den Ordner Examples aus minx´s OpenGL UDF kopieren
autoit.de/wcf/attachment/20867/autoit.de/wcf/attachment/20872/autoit.de/wcf/attachment/20877/
Wer Lust hat, kann ja 2 Texturen erstellen, schön wäre der durch den Tunnel fliegende mit der Mandelbrot-Oberfläche rotierende Würfel....ob das was für die nächste Revision in 1K wäre^^