Master-Seminar Computergrafik SS 2007

Transcrição

Master-Seminar Computergrafik SS 2007
Master-Seminar Computergrafik SS 2007
General Purpose Computation on Graphics Processing Unit
Autor: Stefan Auer
Technische Universität München
General Purpose computation on Graphics Processing Unit
Abstract
GPGPU steht für General Purpose computation on Graphics Processing Unit. Da Grafikprozessoren
(GPUs) im Laufe der Entwicklung immer weiter programmierbar gemacht wurden, kann ihre hohe Leistung
heute auch zur Berechnung von mehr als nur Computergrafik genutzt werden. Diese Arbeit beschäftigt sich
mit der allgemeineren Nutzung des Grafikprozessors als Coprozessor zur Bearbeitung rechenintensiver,
datenparalleler Probleme.
Motivation
GPUs handelsüblicher Grafikkarten haben sich zu leistungsfähigen Parallelrechnern entwickelt, die mit
ihrer Floatingpoint-Leistung vergleichbare CPUs bei geeigneten Anwendungen weit übertreffen. (Theoretische Leistung Nvidia G80 auf 8800GTX: 86 GB/s Speicherbandbreite, 345 Gflops Floatingpoint Leistung;
Vergleich Intel Core 2 Quad Q6600: ~5 GB/s Speicherbandbreite, ~40 Gflops Floatingpoint Leistung) Aufgrund ihrer unterschiedlichen Hardware-Architektur profitieren GPUs mehr als CPUs von den Verbesserungen der Fertigungsprozesse. Eine erhöhte Transistorzahl lässt sich hier leichter in direkte Steigerung der
Leistung umwandeln, so dass der Leistungszuwachs in den letzten Jahren bei den GPUs höher war. (Leistungszuwachs Nvidia 8800 GTX (2007) zu 6800 GT (2004) ca. 1350%; Intel Core 2 Quad Q6600 (2007) zu
Pentium 4 600 (2004) ca. 500%)
Das Hauptanwendungsgebiet leistungsstarker GPUs ist die Darstellung von Echtzeit-3D-Grafik in Computerspielen. Computer und Videospiele sind ein Endverbraucher-, Massenmarkt in dem MilliardenUmsätze gemacht werden. Da dadurch auch die notwendige Hardware ein Massenprodukt darstellt sind
die Grafikkartenpreise im Vergleich zu ähnlich leistungsfähiger Spezial-Hardware verschwindend gering. Die
Kombination aus enormem Leistungspotential, günstigem Preis und weiter Verbreitung hat GPUs in das
Interesse von Forschern und Entwicklern gerückt, welche diese gerne allgemein zur Bearbeitung rechenintensiver Floatingpoint-Probleme zweckentfremden würden.
Hardware Design aktueller GPUs
Pipeline
Aus der Spezialisierung auf Echtzeit-3D-Rastergrafik ergab sich für alle GPUs ein ähnliches HardwareDesign, welches sich auch in der gängigen Hardware-Abstraktion in Grafik-APIs, der Rendering Pipeline,
wiederspiegelt. Gemäß diesem Konzept durchläuft alle 3D-Geometrie, welche eine Anwendung auf den
Bildschirm darstellen will, dieselben Pipeline Stufen: Bildung der Input-Datenströme, Vertex-Verarbeitung
(z.B. Transformation, Beleuchtung), Geometrie-Verarbeitung (z.B. Backface Culling), Rasterisierung, Fragment-Verarbeitung (z.B. Texturierung), Zusammenfassen des Fragment Outputs im Framebuffer (z.B. ZTest, Alphablending).
Diese Stufen finden sich mehr oder weniger direkt auch im GPU-Hardware-Design wieder, wo es bis zur
letzten DirectX9-Generation gesonderte Vertex-Prozessoren, Fragment-Prozessoren und Raster-OperationPipelines gab, durch welche die Daten sozusagen der Reihe nach geschleust wurden. Die aktuelle GPUGeneration nutzt dagegen meist eine Unified-Shader-Architektur, was bedeutet dass ein einziger Prozessortyp die Vertex-, Geometrie- und Fragment-Verarbeitung übernimmt. Die Daten werden dabei in einer Art
Schleife mehrmals von den gleichen Prozessoren aber mit unterschiedlichen Programmen (Kernels) bearbeitet.
Das Konzept der Unified Shader bringt für das Rendering Vorteile wie bessere Lastverteilung zwischen
den unterschiedlichen Pipeline-Stufen und für die GPU-Hersteller mehr Flexibilität bei der Implementierung
der Pipeline (z.B. ist dadurch für Geometrie-Shader kein zusätzlicher Prozessoren-Typ notwendig). Die Verallgemeinerung und Flexibilisierung der Shader-Prozessoren macht die Hardware aber natürlich auch für
GPGPU um einiges interessanter. Vergleicht man dabei die Programmierung von GPUs mit der von CPUs
muss man beachten, dass beide unterschiedliche Architekturen implementieren.
CPU- vs. GPU-Architektur
CPUs folgen der Von-Neumann-Architektur: Daten und Programme befinden sich im selben Speicher.
Programme werden als Ströme von Instruktionen angesehen, welche jeweils wahlfreien Zugriff auf die Daten im Speicher haben. Der wahlfreie (und teilweise schlecht vorhersehbare) Speicherzugriff macht sehr
aufwändiges Caching notwendig, um die Speicher- Latenz als Flaschenhals (Von-Neumann-Flaschenhals) zu
minimieren. CPUs weisen daher relativ zu GPUs nur geringe ALU-Leistung (nur 6.5% der Die-Oberfläche
eines Itaniums werden für Integer- und Floatingpoint-Arithmetik genutzt) und niedrige Speicherbandbreiten auf. Soweit echt parallele Verarbeitung unterstützt wird (Mehrkernprozessoren), profitieren hauptsächlich aufgabenparallele Probleme (z.B. Ausführung mehrerer völlig unterschiedlicher, unabhängiger Prozesse/Threads) davon.
GPUs dagegen folgen näherungsweise der Stream-Processing-Architektur: Dabei werden die Programme als feststehende Verarbeitungsstationen (Kernel) angesehen durch welche die Daten als Ströme, der
Reihe nach oder untereinander verzweigt, hindurch geschleust werden. Die Voraussetzung damit diese
Architektur funktioniert, ist dass die Daten eine große Zahl gleichartiger Objekte repräsentieren, welche
größtenteils unabhängig voneinander verarbeitet werden können (Datenparallelität). Der Vorteil dieser
Architektur ist, dass die hohe Speicher-Latenz dabei kaum eine Rolle spielt und so mehr HardwareRessourcen für die Verarbeitung arithmetischer Operationen und Erhöhung der Speicherbandbreite zur
Verfügung stehen. Nachteilig sind die Einschränkung auf datenparallele Probleme und die geringere Flexibilität der Programme (Kernel sollten „kleine“ Programme bleiben und auf bedingte Sprünge soweit wie möglich verzichten).
GPGPU mit Standard APIs
Computational Grids
Nachfolgend wird mit „Texturen als Computational-Grids“ der naheliegendste Weg vorgestellt GPUs
unter Verwendung von Standard-Grafik-APIs wie Direct3D oder OpgenGL zur allgemeinen Berechnung anstatt zum Rendering zu benutzen. Dabei repräsentieren die Texel die zu verarbeitenden Datenobjekte, Texturen die Datenströme und Fragment-Programme die Kernel welche die Daten verarbeiten. Ein „Pass“ der
Berechnung erfolgt dabei durch das Zeichnen eines Fullscreen Rechtecks via render-to-texture auf eine
Ausgabe-Textur.
Dazu wird die Render-Target-Größe auf die Größe der Ausgabe-Textur gesetzt und der Vertex-Shader
konfiguriert „nichts zu tun“ (d.h. die Vertex-Koordinaten entsprechen bereits den „Bildschirmkoordinaten“). Man lädt und bindet den jeweiligen Kernel als Fragment-Programm, eine oder mehrere Texturen als
Eingabeströme und die Ausgabe-Textur als Render-Target. Zeichnet man nun ein Dreieck über den gesamten „Bildschirmbereich“, so generiert der Rasterizer für jedes Texel der Ausgabetextur ein Fragment für
welches der Kernel als Fragment-Shader ausgeführt wird. Im Shader-Programm kann über Texture-Sampler
wahlfrei auf die in den Input-Texturen enthaltenen Daten zugegriffen werden (Gather) und beliebiger Shader-Code genutzt werden um daraus die Ergebnisse zu erzeugen, die als Pixel bzw. Texel in der AusgabeTextur landen.
GPGPU Techniken
Viele einfache Mechanismen, Algorithmen und Datenstrukturen, die bei gewöhnlicher CPU Programmierung gang und gäbe sind, werden in Shader-Programmen nicht von Haus aus angeboten und müssen
über Umwege realisiert werden. Zu diesen „GPGPU Tricks“ zählt auch die Nachbildung des (in Shader-Code
nicht unterstützten) Scatters, also des Schreibens von Daten an wahlfreie Speicherpositionen. Dazu kann
man, je nach Anforderungen, unterschiedliche Techniken einsetzen wie: 1) Ermitteln der Ergebnisse in Pass
eins; Aufsammeln an den bereits vorab (statisch) bekannten Positionen in Pass zwei. 2) Speichern der Er-
gebnisse und Ziel-Adressen in Pass eins; Sortieren nach Adressen in Pass zwei; Aufsammeln der Ergebnisse
an den Ziel-Positionen durch Binäre Suche in Pass drei. 3) Berechnung durch Zeichnen von Punkten im Vertex-Shader durchführen (dort kann Zielposition verändert werden). 4) Speichern der Ergebnisse und der
Adressen im Fragment-Shader in Pass eins ; Wert-Adress-Zuordnung im Vertex-Shader in Pass zwei.
Weitere wichtige GPGPU Techniken: (aufgrund von Umfang und Komplexität nicht genauer erläutert)
Zeilen- / Spaltenweises oder Blockweises Zusammenfassen von Ergebnissen (Reduce); Filterung der Ergebnisse; Sortierung über Sorting-Networks; parallele Suchalgorithmen; unterschiedlichste Formen von Datenstrukturen (z.B. dünnbesetzte Matrizen, adaptive Datenstrukturen wie shadow maps); Branching (statisch
durch zeichnen nur bestimmter Bereiche; Nutzung des z-Buffers; Verwerfen von Ergebnissen durch bedingte Writes; Nutzung mathematischer Ersatzkonstrukte; Branching-Unterstützung in Shadermodel 3 und 4)
Anwendungsbeispiele
GPGPU unter Verwendung von Standard-Grafik-APIs wird bisher schon in unterschiedlichsten Anwendungsbereichen genutzt. So gibt es Partikel-Systeme und Fluid-Simulationen deren gewöhnlichen und partiellen differentiellen Gleichungen auf der GPU gelöst werden, Lineare Algebra Systeme die z.B. in numerischen Simulationen eingesetzt werden können oder GPU unterstützte Raytracer. GPUs werden ebenso
eingesetzt um Datenbank Querys durch schnellere Joins zu beschleunigen, Simulationen auf Basis der finiten Differenzen- und finiten Elementen Methode durchzuführen oder für Bildverarbeitungsprobleme aus
Bilderkennung und Computervision. Unter anderem mit realtime global illumination und Dynamik Simulationen existieren auch bereits Anwendungen die eher wieder Verwendung in den verbreiteteren GPUAnwendungen, den Computerspielen, finden dürften.
GPGPU alla Nvidia
Nachteile von Standard Grafik APIs
OpenGL und Direct3D wurden ausschließlich zum Rendern von 3D-Rastergrafik entwickelt und weisen
daher bei der Verwendung für grafikfremde Probleme eine Reihe von Nachteilen auf. Vetices, Primitive und
Fragmente, auf denen die Shader-Programme der APIs arbeiten, sind reine Grafikabstraktionen, die für
allgemeine Probleme unpassend sind. Nur wenige nicht-Grafik-Experten dürften gewillt sein, sich das Computergrafikfachwissen anzueignen, das notwendig ist um sinnvolle GPGPU-Programme mit Standard-3DAPIs zu erstellen. Hinderlich sind auch der umständliche Umgang mit dem Speicher (fehlender Scatter) und
die Tatsache, dass viele kritische Entscheidungen von Grafik-API und Treibern getroffen werden, die sich
ständig ändern und oft für die GP-Anwendung kontraproduktive Optimierungen enthalten.
CUDA: Einführung
Da aber glücklicherweise auch die führenden GPU-Hersteller den GPGPU Trend mitbekommen haben,
entwickelten sie Software Plattformen, mit denen sich die Grafik-Chips besser für allgemeine Aufgaben
verwenden lassen. Das entsprechende Produkt von Nvidia heißt CUDA, was für „Compute Unified Device
Architecture“ steht. Dabei handelt es sich um eine GPGPU Plattform die sich erst mit dem aktuellen G80
und zukünftigen Grafik-Prozessoren nutzen lässt. Bei CUDA wird zur Programmierung der Grafikkarte das CSubset von C++ verwendet und herkömmliches Grafik-API und –Treiber sind nicht mehr notwendig (wenn
auch weiterhin parallel via Betriebssystem-Multitasking nutzbar).
CUDA: Funktionsweise
Programmierer die die GPU als Coprozessor nutzen wollen, müssen entweder auf die mitgelieferten
CUDA Libraries (enthalten z.B. Funktionen für FFT) zurückgreifen oder selbst Teile ihrer Programme für CUDA schreiben. CUDA-Programme, die sowohl normalen CPU / C++ Code als auch GPU / C Code enthalten,
werden mit dem NVCC Compiler Driver übersetzt. Dieser trennt CPU von GPU Code, wobei ersterer mit
CUDA-Aufrufcode angereichert und konventionell übersetzt oder an einen vorhanden C++-Compiler weitergeleitet wird. Der GPU-Code wird in Zwischen-Code für die PTX virtuelle Maschine übersetzt, welcher
erst bei der Programminstallation vom CUDA-Treiber in Maschinencode für die installierte GPU übersetzt
wird.
Im CUDA-Programmiermodell wird die GPU als Coprozessor der CPU angesehen. Datenparallele Programmteile, werden in besonders gekennzeichnete Funktionen ausgelagert, welche später als Kernel auf der
GPU laufen. Die Kernel-Ausführung geschieht implizit parallel in üblicherweise tausenden Threads, welche
jeweils auf unterschiedlichen Daten arbeiten (vergleichbar SIMD-Konzept). CPU und GPU verfügen jeweils
über ihre eigenen Speicher (Host-Speicher, Device-Speicher), zwischen denen via DMA hin- und her-kopiert
werden kann. Für die GPU-Ressourcen Zuteilung (Threads, Register, Speicherbereiche) ist der Programmierer verantwortlich, welcher den zugehörigen Speicherbereich bei Variablen und die Thread-Aufteilung bei
Kernel-Aufrufen bestimmt.
CUDA: Threads
Das Threadmanagement gliedert die CUDA-Threads hierarchisch in Grids und Blöcke. Ein Grid repräsentiert dabei alle Threads eines einzelnen Kernelaufrufs, ein Block alle Threads die zusammen von einem einzelnen Shader-Multiprozessor der GPU verarbeitet werden. Grids können bis zu 65535 hoch 2 Blöcke
enthalten und werden ein- oder zweidimensional indiziert. Blöcke enthalten bis zu 512 Threads und werden
ein-, zwei- oder dreidimensional indiziert.
Jeder der aktuell (G80) bis zu 16 Shader-Multiprozessoren der GPU führt zu einer Zeit jeweils nur einen
aktiven Block aus, kann diesen aber via Scheduling aus bis zu 8 Blöcken wählen. Mit jeder Ausführung einer
Instruktion werden alle 32 Threads eines sogenannten „Warps“ gemeinsam verarbeitet. Dadurch ergeben
sich je nach Komplexität der Instruktion Laufzeiten von 4 bis 32 Taktzyklen je Warp (einfache Instruktion, 8
Stream-Prozessoren je Multiprozessor => 32/8=4 Taktzyklen).
CUDA: Speicherbereiche
Die unterschiedlichen CUDA Speicherbereiche orientieren sich ebenfalls am Grid/Block/ThreadKonzept. Jedem einzelnen Thread sind eine gewisse Zahl sehr schneller R/W-Register (Register pro ShadingMultiprozessor / Blockgröße = Register pro Thread; G80: 8192 Register pro SM) und ein sehr langsamer,
ungecachter R/W-Device-Speicherbereich (local memory) zugeordnet. Alle Threads eines Blocks teilen sich
den schnellen R/W-Shared-Memory (G80: 16kB) ihres Multiprozessors, auf welchen sie mittels Ausführungsbarrieren (alle Threads müssen Code-Stelle erreichen, bevor weitergemacht wird) und atomaren Operationen (Read-Modify-Write; erst in neuersten Hardware-Versionen verfügbar) auch mehr oder weniger
synchronisiert zugreifen können. Alle Threads eines Grids teilen sich den sehr langsamen, ungecachten
R/W-Global-Device-Memory (keine Synchronisation möglich, vergleichbar Framebuffer), den schnellen
gecachten Readonly-Constants-Device-Memory (vergleichbar Shader-Konstanten; G80: 64kB) und den mittelmäßig schnellen Readonly-Texture-Device-Memory (Device-Memory insgesamt G80: bis zu 768 MB). Der
Host kann vor und nach einem Kernel-Aufruf lesend und schreibend auf Constants-, Texture- und GlobalMemory zugreifen.
CUDA: Spracherweiterungen
Die C/C++ Programmiersprache wurde für CUDA mit ein paar Erweiterungen ausgestattet: Der „Ausführungsort“ einer Funktion wird mittels der Schlüsselwörter __host__ (Aufruf und Ausführung auf der CPU;
kann auch weggelassen werden), __global__ (Aufruf auf der CPU, Ausführung auf der GPU; entspricht
Kernel) und __device__ (Aufruf und Ausführung auf der GPU; implizites Inlining) angegeben. (host und
device auch kombinierbar => doppelte Kompilierung) Der Speicherort einer Variablen wird durch Angabe
von __device__ , __constant__ und __shared__ bestimmt. Mithilfe der sogenannten Kernel Ausführungskonfiguration Funktionsname<<<Gridsize, Blocksize>>>(...) wird beim Aufruf einer Global-Funktion bestimmt, auf wie vielen Blöcken je Grid und wie vielen Threads je Block der Kernel ausgeführt
wird. Die integrierten Variablen gridDim, blockIdx, blockDim, threadIdx geben innerhalb einer
Kernelfunktion an, mit welcher Ausführungskonfiguration diese gestartet wurde und um welchen Thread
bzw. Block es sich aktuell handelt. Mithilfe der Speicherverwaltungsfunktionen cudaMalloc(…),
cudaFree(...), cudaMemcpy(...), cudaMemcpy2D(...) kann Speicher auf dem Device allokiert
und freigegeben, sowie zum und vom Host kopiert werden.
CUDA: Bewertung und Zukunft
CUDA ist eine Programmier-Plattform, die von vornherein auf die Nutzung der GPU als Coprozessor zur
Berechnung allgemeiner datenparalleler Probleme ausgelegt ist. Als solche ist sie für nicht-Grafik-nahe
GPGPU-Anwendungen sicherlich besser geeignet als ein Grafik-API und hat aufgrund der leichteren Zugänglichkeit auch das Zeug dazu möglicherweise eine kritische Masse von nicht-Grafik-Programmierern für
GPGPU zu interessieren.
Handelt es sich bei einer Anwendung allerdings beispielsweise um eine Visualisierung, so haben die
Grafik-APIs den Vorteil, dass die Daten gleich dort berechnet werden, wo sie auch angezeigt werden können. Zudem sind Direct3D und OpenGL im Gegensatz zu CUDA ausgereifte und gut dokumentierte Systeme,
welche von vielen Entwicklern bereits beherrscht werden. Ein weiterer Vorteil der Grafik-APIs ist, dass sie
nicht nur mit Nvidia Produkten, sondern mit allen verfügbaren Grafik-Chips funktionieren, was beispielsweise bei Spielen das ausschlaggebende Kriterium sein könnte.
Um kommerziell einen Gewinn aus den eigenen GPGPU-Bemühungen zu ziehen, bietet Nvidia mittlerweile unter dem Label „Tesla“ spezialisierte GPGPU-Hardware an. Dabei handelt es sich bisher im Grunde
um normale GPUs, verbaut in unterschiedlichen Geräten (Einschubkarte, Workstation, Server-Rack) mit
besserem Speicherausbau. Für die Zukunft plant man jedoch neue, ausschließlich GPGPU relevante Features wie double-precition-floatingpoint-Unterstützung nur bei den Tesla-Produkten freizuschalten. Der Erfolg der Tesla-Produkte könnte für die Weiterentwicklung von CUDA maßgeblich sein, was man sowohl
positiv, als auch negativ bewerten könnte.
GPGPU alla AMD/ATI
Auch bei AMD/ATI hat man sich Gedanken über die mögliche Zukunft von GPGPU gemacht. Im Zuge
der Übernahme des GPU-Spezialisten ATI durch AMD präsentierte man den Aktionären und der Öffentlichkeit unter dem Codenamen „Fusion“ erste Pläne CPU- und GPU-Kerne gemeinsam auf einem Prozessor-Die
unterbringen. Soll es sich bei den ersten, für 2009 erwarteten, Produkten noch hauptsächlich um stromsparende Billigprozessoren für Notebooks handeln, so möchte man bis ca. 2015 zusätzlich Nutzen für die Rechenleistung aus der CPU-GPU-Verschmelzung ziehen. Dabei ist es angedacht, die GPU-Kerne neben der
Grafikdarstellung auch als Streaming-Coprozessor für datenparallele Berechnungen zu nutzen.
Während Fusion noch reine Zukunftsmusik ist (die möglicherweise hauptsächlich gebracht wurde, um
die Übernahme vor den Aktionären zu begründen), ist ein anderes Produkt von ATIs GPGPU-Bemühungen
schon seit längerem verfügbar: Hinter „Close to metal“ (CTM) verbirgt sich die Implementierung von ATIs
„Data parallel virtual machine“ (DPVM) Konzept für die Radeon R580er Serie (verbaut in Radeon X19x0
Serie und AMD StreamProcessors ehemals ATI FireStream). Die DPVM stellt eine Software-Plattform für
GPGPU-Programme dar, welche die GPU, unter Umgehung von Grafik API und Treiber, direkt als Prozessor
nutzen. Die virtuelle Maschine abstrahiert die GPU auf einfache Art und Weise als einen „Command Prozessor“, der die in Command-Buffern bereitgestellten Tasks auf die Streaming Prozessoren des „Data parallel
processor arrays“ verteilt und einen „Memory controler“ der sämtliche Speicherzugriffe und –transfers
regelt.
CTM, die Implementierung der DPVM, besteht aus einer Spezifikation der Architektur (ISA, Ressourcen,
etc.), der Runtime (implementiert als low-level Treiberkomponenten) und den Support Librarys welche die
Generierung von Command-Buffern aus GPU-Assembler-Code sowie die Speicherallokation ermöglichen.
High Level Programmiersprachen oder sonstige Entwicklungstools werden von ATI bisher nicht angeboten,
sondern diese sollen nach Möglichkeit von Dritten (wie z.B. den Entwicklern von BrookGPU?) realisiert
werden. Dementsprechend werden die Vorteile, wie der direkte Zugang zur Hardware unter Ausblendung
grafikspezifischer Features, wohl nur von Forschern und Entwicklern genutzt werden die gewillt sind, sich
ernsthaft mit einem neuen GPU-Assembler und den Details der R580 Plattform zu beschäftigen (für den
R600 ist bisher nichts Vergleichbares verfügbar).
Quellen
 www.GPGPU.org
 CSE Stony Brook GPGPU Kurs
http://www.cs.sunysb.edu/~mueller/teaching/cse690/syllabus.html
 ECE Illinois CUDA Kurs
http://courses.ece.uiuc.edu/ece498/al/Syllabus.html
 IEEE Visualization 2005 Tutorial
http://www.gpgpu.org/vis2005
 SIGGRAPH 2005 GPGPU Kurs
http://www.gpgpu.org/s2005
 A Survey of General Purpose Computationon Graphics Hardware
http://www.cs.virginia.edu/papers/ASurveyofGeneralPurposeComputationonGraphicsHardware.pdf
 A GPU Framework for Interactive Simulation and Rendering of Fluid Effects
http://mediatum2.ub.tum.de/doc/604112/document.pdf
 John Owens - What’s New with GPGPU?
http://www.ece.ucdavis.edu/~jowens/talks/berkeley-glunch-060831.pdf
 John Owens - GPU Computing
http://www.cgo.org/cgo2007/presentations/cgo2007-keynote-buck.pdf
 A performance oriented data parallel virtual machine for GPUs
http://ati.amd.com/developer/siggraph06/dpvm_sketch_siggraph.pdf
 Brent Oster - CUDA
http://www.cs.ucsb.edu/~gilbert/cs240aSpr2007/lectures/G80%20CUDA.ppt
 Hochschule Bremen GPGPU Semesterarbeit
http://www.weblearn.hs-bremen.de/risse/RST/WS06/GPGPU/GPGPU.pdf
 University of Virginia Realtime-Rendering Kurs
http://www.cs.virginia.edu/~gfx/Courses/2006/RealTime/lecture21.GPGPU.ppt
 Nvidia CUDA Programming Guide
http://developer.download.nvidia.com/compute/cuda/1_0/NVIDIA_CUDA_Programming_Guide_1.0.
pdf
 Mike Houston - GPGPU
http://graphics.stanford.edu/~mhouston/public_talks/R520-mhouston.pdf
 GPU Gems 1 und 2
 Wikipedia
http://en.wikipedia.org/wiki/Gpgpu

Documentos relacionados