Post on 20-Mar-2022
Volt: Interaktives Volumenrendering mit CUDA
Oliver Jato, André Hinkenjann
Labor für Computergra�k
Hochschule Bonn-Rhein-Sieg
Grantham-Allee 20
53757 Sankt Augustin
Tel.: +49 (0)2241 / 865 - 229
Fax: +49 (0)2241 / 865 - 8229
E-Mail: {oliver.jato@inf.h-brs.de|andre.hinkenjann@h-brs.de}
Zusammenfassung: In diesem Beitrag wird der interaktive Volumenrenderer Volt für die
NVIDIA CUDA Architektur vorgestellt. Die Beschleunigung wird durch das Ausnutzen der
technischen Eigenschaften des CUDA Device, durch die Partitionierung des Algorithmus
und durch die asynchrone Ausführung des CUDA Kernels erreicht. Parallelität wird auf dem
Host, auf dem Device und zwischen Host und Device genutzt. Es wird dargestellt, wie die
Berechnungen durch den gezielten Einsatz der Ressourcen e�zient durchgeführt werden. Die
Ergebnisse werden zurückkopiert, so dass der Kernel nicht auf dem zur Anzeige bestimmten
Device ausgeführt werden muss. Synchronisation der CUDA Threads ist nicht notwendig.
Stichworte: Volumenrendering, Ray Casting, 3D Visualisierung, CUDA, Echtzeit
1 Einleitung
Interaktivität, hohe Visualisierungsqualität und günstige Hardware waren für lange Zeit Zie-
le, die sich im Feld der Volumenvisualisierung nicht miteinander vereinbaren lieÿen. Dass
Volumendaten besonders zur Darstellung ober�ächenloser Phänomene geeignet sind spricht
für direkte Verfahren wie das Ray Casting, das in diesem Zusammenhang auch als direktes
Volumenrendering bezeichnet wird. Zusätzlich ist Ray Casting durch die erreichbare visuelle
Qualität anderen Verfahren überlegen. Der Rechenaufwand und die Anforderungen an den
Speicher sind allerdings hoch. Es handelt sich um ein Bildraumverfahren. Pro Bildpunkt
wird ein Sehstrahl abgetastet und für jeden einzelnen Abtastpunkt sind mehrere unregel-
mäÿige Speicherzugri�e nötig. Interpolationen und Beleuchtungsberechnungen müssen auf
Basis von Nachbarschaften durchgeführt werden. Dabei ist Ray Casting aber hervorragend
parallelisierbar. Die Berechnungen der einzelnen Sehstrahlen sind voneinander unabhängig
und es ist ein �exibler und unkomplizierter Algorithmus, der einfach zu erweitern ist.
Angetrieben durch den Entertainment Bereich steigt die Leistung und Flexibilität von
GPUs beständig an. Ursprünglich stellten sie eine Pipeline mit fester Funktionalität zur Ver-
fügung, heutzutage sind sie sehr frei programmierbar. Um seine GPUs gänzlich für gra�kferne
Programmierung zu ö�nen, hat der Hersteller NVIDIA die CUDA Architektur entworfen.
Hierdurch stehen kostengünstige massiv parallele Systeme zur Verfügung, die mehrere hun-
dert Rechenkerne mit Zugri� auf einen gemeinsamen Adressraum besitzen. Durch CUDA
ist es möglich, hochwertige interaktive Volumenvisualisierung auf aktueller und verbreiteter
Standardhardware zu betreiben. Dies kann aber nur erfolgreich sein, wenn die technischen
Eigenschaften der Hardware beachtet werden.
Nach einer Betrachtung bisheriger Entwicklungen im Volumenrendering (Abschnitt 2),
besonders im Bereich der GPUs, wird der Volumenrenderer Volt [Jat10] (Abb. 1) vorge-
stellt. An seinem Beispiel wird gezeigt, wie der grundlegende Algorithmus zum direkten
Volumenrendering e�zient mit CUDA umgesetzt werden kann, so dass gleichzeitig hohe
Visualisierungsqualität und Interaktivität erreicht werden. Dazu wird ein Überblick über
den angewendeten Visualisierungsalgorithmus und die Anwendungsarchitektur gegeben (Ab-
schnitt 3). Danach werden Eigenschaften des Kernels beschrieben und relevante Parameter
der CUDA Architektur betrachtet (Abschnitt 4). Abschlieÿend folgen Ergebnisse (Abschnitt
5) und das Fazit (Abschnitt 6).
Abbildung 1: Volt Volumenrenderer mit Transferfunktionseditor
2 Stand der Technik
Slicing In [CN94] wird Volumenvisualisierung durch Verwendung von Texturhardware als
Slicing beschrieben. Das verwendete Silicon Graphics RealityEngine-System unterstützt drei-
dimensionale Texturen. Das Volumen wird an äquidistant geschichteten Schnittebenen ab-
getastet, wodurch Proxygeometrie texturiert wird. Hier wird bereits die Texturhardware zur
schnellen trilinearen Interpolation genutzt. Die texturierten Polygone werden im Back-To-
Front Verfahren zusammengefügt. Bei perspektivischer Projektion sind die Abstände der
Abtastpunkte auf den verschiedenen Sehstrahlen unterschiedlich. Werden statt einer dreidi-
mensionalen Textur drei zweidimensionale Texturstapel verwendet, so variiert der Abstand
zusätzlich noch mit dem Betrachtungswinkel.
In [WE98] wird Slicing um di�use Schattierung für Isoober�ächen erweitert. Dazu werden
die Materialgradienten im Voraus berechnet, normalisiert und zusammen mit den Dichtewer-
ten in einer 3D-Textur gespeichert. Die Berechnung des Gradienten für einen Abtastpunkt
führt hier aber zu Artefakten in der Schattierung, da die Interpolation der umliegenden
Gradienten durch die GPU keinen normalisierten Vektor mehr zum Ergebnis hat.
Prä-Integration wird in [EKE01] für Slicing umgesetzt. Damit sind Volumen mit hoch-
frequenten Transferfunktionen ohne Erhöhen der Abtastrate darstellbar. Gleichzeitig kann
das Volumenrenderingintegral genauer approximiert werden, ohne dass sich dies auf die Ge-
schwindigkeit auswirkt. Dabei werden alle möglichen Strahlsegmente in einem Vorverarbei-
tungsschritt integriert und die Ergebnisse in einer Textur gespeichert. Da der Berechnungs-
aufwand für diese Textur hoch ist, gestalten sich Änderungen an Farbe und Opazität zur
Laufzeit schwierig. An den Abtastpunkten lässt sich zudem keine zuverlässige Schattierung
für das gesamte Strahlsegment berechnen.
Die Parallelisierung von Slicing wird in [MHE01] und [MWMS07] untersucht. Die Volu-
men werden für ein Sort-Last Verfahren in kleinere Blöcke unterteilt und auf einem Cluster
berechnet.
Ray Casting In [PBMH02] wird erstmals Ray Tracing auf programmierbarer Gra�khard-
ware implementiert. Darauf folgen [KW03] und [RGW+03] mit Volumenrenderern, die Early
Ray Termination (ERT) und Empty Space Leaping nutzen. Die Approximation von Licht-
streuung und volumetrischen Schatten wird in [KPH+03] beschrieben. In [SSKE05] wird
erstmals ein Single-Pass Algorithmus vorgestellt, da die Nutzung von Schleifen und Ver-
zweigungen in Shaderprogrammen möglich geworden ist.
Die Entwicklung des Prototypen eines Volumenrenderers für CUDA hat in [MHS08] zum
Ergebnis, dass die gewonnene Flexibilität keine Einbuÿen in der Performanz mit sich bringt.
In [ZCC09] wird ebenfalls von einer Implementierung für CUDA berichtet, die im Vergleich
zur eigenen, älteren Implementierung mit einer Shadersprache, schneller sein soll.
In [MRH10] wird eine Technik beschrieben, die Zugri�e auf den Texturspeicher verringert.
Die Sehstrahlen eines CUDA Thread Block erhalten denselben Startpunkt und schreiten
das Volumen als Strahlenfront ab. Der Shared Memory des Device wird als Cache für die
Samples verwendet. Ist der Cache gefüllt, werden die Strahlen von ihrer letzten Startposition
neu abgeschritten und alle Berechnungen werden auf Grundlage des Caches durchgeführt.
Bei Perspektivprojektion sind die Materialgradienten hierdurch weniger genau und zur ERT
müssen alle Strahlen eines Thread Blocks die maximale Sättigung erreicht haben. Dieses
Verfahren steigert die Performanz, wenn für Berechnungen oft auf dieselben Voxel zugegri�en
werden muss.
3 Anwendungsarchitektur
3.1 Visualisierungsalgorithmus
Zur Abtastung des Datenraumes wird direkte Volumenvisualisierung im Front-To-Back Ver-
fahren angewendet. Vom Volumen emittierte Strahlung wird an den Abtastpunkten durch
approximative Sehstrahlintegration akkumuliert. Dabei wird auch Absorption durch Über-
deckung berücksichtigt. Um hohe Frequenzen im Volumen mit möglichst geringem Fehler
darstellen zu können wird Postklassi�kation verwendet. Die Übersetzung der Funktionswerte
zu Farbe und Opazität wird an jedem einzelnen Abtastpunkt erst nach seiner Rekonstruk-
tion vorgenommen. An jedem Abtastpunkt, dessen Opazität einen geringen Schwellenwert
überschreitet, wird der Materialgradient berechnet. Dieser dient als Approximation einer
Ober�ächennormalen zur Schattierung nach dem Blinn-Phong Modell. Die Opazität homo-
gener Bereiche kann zur Betonung von Materialgrenzen abgesenkt werden.
Um den Anwender bei der Exploration von Volumen zu unterstützen, können die Far-
ben und Opazitäten der rekonstruierten Werte über einen Transferfunktionseditor interaktiv
verändert werden. Abweichungen in der Transparenz des Volumens durch Ändern der Ab-
tastrate werden dabei mit Opazitätskorrektur auf Basis der Integrationsschrittweite vermie-
den. Durch die Gewichtung der Farbwerte mit den Opazitäten (assoziierte Farben) in der
Look-Up-Table (LUT) der Transferfunktion wird Color Bleeding zwischen transparenten und
opaken Bereichen verhindert.
Zur Bestimmung der Start- und Endpunkte auf den Sehstrahlen kommen ein Bounding
Box Schnitttest nach der Kay & Kajiya Slab-Method und ERT zum Einsatz.
3.2 Aufgabenpartitionierung
Ziel der Architektur und Aufgabenpartitionierung ist es, die optimale Auslastung des Device
zu gewährleisten und ein Blockieren der gra�schen Ober�äche zu verhindern, da die Transfer-
funktion zur Manipulation der optischen Eigenschaften der Volumendaten zur Laufzeit bear-
beitbar sein soll. Die Anwendung ist horizontal und vertikal partitioniert (Abb. 2). Sie stellt
eine mehrstu�ge Pipeline dar, deren Abschnitte durch unterschiedliche Host Threads bear-
beitet werden. An den Synchronisationspunkten werden über Pu�erobjekte Speicheradressen
getauscht. Der CUDA Kernel führt nur Berechnungen durch, die von einem Sehstrahl ab-
hängig sind und die Farbe eines Bildpunktes zum Ergebnis haben. Alle Berechnungen, die für
jeden CUDA Thread dieselbe Eingabe und dasselbe Ergebnis hätten, werden zuvor auf dem
Host durchgeführt. Aus diesem Grund wird auch die Opazitätskorrektur mit einer Potenz-
funktion schon auf dem Host durchgeführt. Zusätzlich wird jede arithmetische Operation,
die auf dem Device kostspielig ist, nach Möglichkeit auf dem Host in eine günstigere Form
gebracht. Muss zum Beispiel jeder CUDA Thread mit demselben Wert eine Division durch-
führen, dann wird auf dem Host das Reziprok berechnet und dieses dem CUDA Kernel als
Teil seiner Kon�guration übergeben. Hierdurch wird das Device deutlich entlastet.
Abbildung 2: Partitionierung der Anwendung auf Host und Device
Benutzerober�äche Im Thread der Benutzerober�äche werden Interaktionen registriert
und fertig berechnete Einzelbilder in das Anwendungsfenster gezeichnet. Werden durch Edi-
toren Änderungen an der Transferfunktion oder an Kon�gurationsparametern vorgenommen,
werden diese ebenfalls registriert und signalisiert.
Szenenkon�guration Die Szenenkon�guration verarbeitet die, im letzten Durchlauf ak-
kumulierten, Benutzereingaben und erzeugt hieraus das Szenenkon�gurationspaket. Hier sind
alle für Interaktivität notwendigen Parameter für den Kernel enthalten. Dies sind der Ort
und die Richtung des ersten Sehstrahls (Firstray), zwei Vektoren zur Bestimmung der Lage
und Kantenlänge der Pixel, die transformierte Bounding Box in Ebenendarstellung für den
Schnitttest und die inverse Transformationsmatrix. Zur Optimierung werden die Daten im
Structure of Arrays Layout organisiert.
Einzelbildberechnung Im Thread zur Einzelbildberechnung muss anfangs die statische
Kon�guration der Szene in einen Kon�gurationsblock geschrieben werden. Er enthält un-
veränderliche Werte, die nur einmal zum Device übertragen werden müssen. Dies sind die
Adresse des Ergebnispu�ers auf dem Device und die Abmessungen der Zeichen�äche. Über
die Ober�äche veränderbare Laufzeitparameter werden, getrennt von der Szenenkon�gurati-
on, in einem Paket zur Laufzeitkon�guration abgelegt. Diese Kon�gurationen werden in der
Regel nicht gleichzeitig durch den Benutzer verändert. Im Laufzeitkon�gurationsblock be�n-
den sich unter anderem die maximale Strahlsättigung für ERT, die normalisierte Schrittweite,
ihr Reziprok und Beleuchtungsparameter. Werden Änderungen an der Transferfunktion oder
an Laufzeitparametern signalisiert, wird durch diesen Thread auch die Aktualisierung durch-
geführt. Er ist auch für die Initialisierung des Device, den Datenaustausch mit ihm und den
Start des Kernels verantwortlich. Vor jedem Aufruf des Kernels wird geprüft, ob erst geän-
derte Daten zum Device übertragen werden müssen. Der Kernel wird asynchron gestartet, so
dass der Host Thread nicht blockiert. Dadurch können schon alle notwendigen Berechnungen
durchgeführt werden, die vor dem nächsten Start des Kernels abgeschlossen sein müssen. Vor
dem nächsten Kernelaufruf muss der Ergebnispu�er vom Device kopiert werden. Da Kernel
und Kopieroperation im Default Stream gestartet werden, blockiert der Host Thread an die-
ser Stelle solange, bis der vorhergehende Kernelaufruf beendet ist. Der Kernel startet sofort
neu, nachdem der Ergebnispu�er und veränderte Kon�gurationen übertragen sind.
Pixelpu�ererzeugung Dieser Thread holt den Ergebnispu�er von der Einzelbildberech-
nung ab. Da die Zeichen�äche nur durch den Thread der Benutzerober�äche manipuliert
werden darf, erhält er über den mit der Zeichen�äche gemeinsamen Pu�er ein durch die
Ober�äche darstellbares Objekt. Dieses befüllt er mit den Daten des Ergebnispu�ers und
signalisiert dann die Notwendigkeit einer Aktualisierung der Zeichen�äche.
4 Volumenrendering mit CUDA
4.1 Kon�guration
Während der Sehstrahlintegration wird unregelmäÿig auf Speicher zugegri�en und der Wert
eines Abtastpunktes muss anhand seiner Nachbarschaft rekonstruiert werden. Daher wird der
Volumenspeicher als CUDA Array alloziert und an eine dreidimensionale Textur für float
Werte gebunden. So werden die auf Lokalität optimierten Texturcaches der Multiprozessoren
(MP) genutzt und beim Auslesen des Volumens wird der Wert am Abtastpunkt von der
Special Function Unit (SFU) des Device durch trilineare Interpolation ermittelt. Für die
LUT der Transferfunktion wird ebenfalls Speicher als CUDA Array alloziert und an eine
eindimensionale Textur gebunden. Da die LUT bei Änderungen neu übertragen werden muss,
liegt sie auf dem Host als Struktur mit einem CUDA float4 Array vor. Dies garantiert
zum einen korrektes Speicheralignment, wodurch die Übertragungsgeschwindigkeit gesteigert
wird, zum anderen wird so die Verwendung der SFU zur Interpolation in den vier RGBA
Kanälen möglich.
Die bereits in Abschnitt 3.2 erwähnten Kon�gurationsblöcke enthalten Variablen, die
von den CUDA Threads nur gelesen werden. Da es allgemeingültige Parameter sind und alle
aktiven Threads eines CUDA Warps sich immer an derselben Programmadresse be�nden,
greifen sie auch simultan auf dieselben Kon�gurationsvariablen zu. Daher wird für die drei
Kon�gurationsblöcke der Constant Memory des Device verwendet, der nur vom Host ver-
ändert werden kann. Für diesen existiert auf jedem MP ein Cache. Wenn alle Threads eines
Warps gleichzeitig dieselbe Adresse im Constant Memory lesen, ist ein Broadcast Speicher-
zugri� möglich. Sobald sich der Wert im Cache be�ndet, ist eine Leseoperation so schnell wie
auf einem Register. Durch die Partitionierung der gesamten Kon�guration in drei Blöcke,
unterschieden nach Aktualisierungscharakteristiken, werden redundante Übertragungen ver-
mieden und die verfügbare Bandbreite besser genutzt.
Für den Ergebnispu�er wird ein Speicherbereich im Global Memory des Device reserviert.
Auf dem Host wird über die CUDA API Page-Locked Host Memory alloziert, was Paging
durch das Betriebssystem verhindert und damit den Kopiervorgang des Pu�ers optimiert.
Die Projektions�äche wird im Sort-First Ansatz uniform unterteilt. Um die Texturcaches
besser zu nutzen, werden den Threads einesWarps benachbarte Sehstrahlen zugewiesen. Die
optimale Vorgehensweise hängt hier von der Hardwarerevision ab. Bei Devices mit Compute
Capability (CC) 1.0 sind Zugri�e auf denGlobal Memory nur in einem Verbund durchführbar,
wenn jeder Thread eines Half-Warps auf das Wort zugreift, dass seinem Index entspricht und
wenn das gesamte Speichersegment am 16-fachen der Gröÿe des Datentyps ausgerichtet ist.
Wird dies nicht beachtet, werden die Operationen auf dem Ergebnispu�er serialisiert. Für die
Anordnung der Sehstrahlen eines Half-Warps bedeutet dies aber, dass Lokalität und somit
die Texturcaches nicht optimal genutzt werden können. Bei neueren Hardwarerevisionen sind
die Bedingungen für verbundene Speicherzugri�e geändert worden. Ab CC 2.0 werden Global
Memory Zugri�e eines gesamten Warp in so viele Einzeloperationen unterteilt, wie unter-
schiedliche L1 Cache Lines (128 Byte) des MP betro�en sind. Sinnvolle Anordnungen der
Threads einesWarps liegen zwischen zwei übereinanderliegenden Reihen zu je 16 Sehstrahlen
und zwei mal vier übereinanderliegenden Reihen zu je vier Sehstrahlen. Die Letzte Kon�gu-
ration erzeugtWarps mit maximaler Ortskohärenz. Wie viele Warps zu einem CUDA Thread
Block zusammengefasst werden können, hängt von der Anzahl verfügbarer Register und der
Belegung des Shared Memory ab. Diese Werte unterscheiden sich ebenfalls zwischen älte-
ren und neueren Devices. Durch mehr Warps pro Block können Read-After-Write Kon�ikte
auf Registern besser verdeckt werden. Weniger Warps pro Thread Block ermöglichen jedoch
mehr aktive Thread Blocks pro MP, wodurch Latenzen von O�-Chip Speicherzugri�en besser
verdeckt werden. Eine optimale Kon�guration wird also durch die verwendete Hardware und
die Charakteristik des ausgeführten Programms bestimmt (siehe auch Abb. 5 und 6). Ein
weiterer Faktor, der durch gesteigerte Ortskohärenz minimiert wird, ist das Divergieren von
CUDA Threads. Führt ein Teil der Threads nur wenige zusätzliche Instruktionen aus, dann
bleiben durch Branch Predication die anderen Threads aktiv, ihrer Berechnungsergebnisse
werden lediglich verworfen. Sind die unterschiedlichen Ausführungspfade zu lang, werden die
Threads in Gruppen parallel verarbeitet, bis sich alle wieder an derselben Programmadres-
se be�nden. Da Threads mit benachbarten Sehstrahlen häu�g dieselben Ausführungspfade
nehmen, wird der parallele Anteil gesteigert.
4.2 Kernel
Im Kernel wird zuerst der Ergebnispu�erindex des Bildpunkts zwischengespeichert und ein
Pu�er für jeden Kanal der akkumulierten RGBA Werte initialisiert. Hierfür wird Shared
Memory verwendet, wodurch die Anzahl der benötigten Prozessorregister verringert wird.
Mit Ausnahme des Alphakanals werden diese Bereiche während der Sehstrahlintegration nur
geschrieben und erst zum Schreiben der Ergebnisfarbe wieder gelesen. Da im Shared Memory
16 (CC 1.0) bzw. 32 (CC 2.0) aufeinanderfolgende 32 Bit Worte in aufeinanderfolgenden
Speicherbänken liegen, müssen Operationen nicht serialisiert werden, da die Threads in Reihe
auf die ihrem Index entsprechenden Worte zugreifen. Solche Shared Memory Operationen
sind in einem Taktzyklus durchführbar.
Im Constant Memory be�nden sich der Firstray und zwei Pixelvektoren. Anhand dieser
berechnet jeder CUDA Thread seinen eigenen Sehstrahl. So ist es nicht nötig, für jeden
Frame alle Sehstrahlen zum Device zu übertragen, obwohl sich die Kamera auf dem Host
be�ndet. Bei der hier und auch an anderen Stellen notwendigen Normalisierung eines Vektors
wird eine reziproke Quadratwurzelfunktion der CUDA API verwendet, wodurch Divisionen
vermieden werden.
Der darau�olgende Bounding Box Schnitttest kann durch den Compiler wegen bedingter
Ausführungen nicht automatisch entrollt werden. Er ist manuell entrollt, wodurch auf die
Angaben zu den Seiten�ächen der Bounding Box im Constant Memory auch nicht dyna-
misch zugegri�en werden muss. Im Schnitttest sind Divisionen nötig, deren Divisor von der
Richtung des Sehstrahls abhängt. Daher kann auf dem Host nicht das Reziprok im Vor-
aus berechnet werden. An dieser Stelle wird eine intrinsische Divisionsfunktion des Device
verwendet. Diese benötigt weniger Prozessorzyklen und die geringere Präzision für Diviso-
ren im Bereich von y−126 bis y126 beeinträchtigt das Ergebnis nicht. Der Dividend besteht
aus dem Punktprodukt der Ebenennormalen mit dem Kameraort und dessen Summe mit
dem Abstand der Ebene zum Ursprung. Diese Berechnung ist unabhängig von Sehstrahlen
durchführbar. Sie wird für jede Ebene schon auf dem Host vorgenommen und ist Teil der
Ebenendarstellung in der Szenenkon�guration.
Im Loop zur iterativen Strahlintegration wird erst der aktuelle Abtastpunkt bestimmt.
Dessen Koordinaten werden aber nicht in einem CUDA float3 Typen abgelegt. Der Compil-
er ist bemüht die Zahl belegter Register zu minimieren um mehr aktive Warps bzw. Thread
Blocks zu ermöglichen. Dynamisch indexierte Arrays und auch Strukturtypen wie die CUDA
Vektortypen können zur Optimierung in den Local Memory ausgelagert werden, was sich ne-
gativ auf die Performanz auswirken kann. Werden statt eines Vektortypen einfache Typen
verwendet, kann der Compiler die Registerbelegung besser optimieren. Aus diesem Grund
wird die Verwendung von CUDA Vektortypen nach Möglichkeit vermieden.
Die Transformationsmatrix wird auf dem Host so berechnet, dass der Abtastpunkt durch
ihre Inverse direkt in das lokale Koordinatensystem der Volumentextur übersetzt wird. Das
Ergebnis kann damit als dreidimensionaler Index zum Auslesen der Textur verwendet werden.
Dieser Wert dient wiederum als Index zum Auslesen des RGBAWertes aus der Transferfunk-
tionstextur. Dass die Opazitätskorrektur schon auf dem Host vorgenommen wird erspart hier
eine teure Potenzfunktion. Liegt die Opazität des Abtastpunktes über einem Schwellenwert,
so wird der Materialgradient an dieser Stelle berechnet, ansonsten werden für Punkte mit
geringem optischen Ein�uss hierdurch sechs Texturzugri�e gespart. An dieser Stelle kann
die Opazität homogener Bereiche abgesenkt werden. Ist die Opazität noch hoch genug, wird
schlieÿlich Blinn-Phong Shading berechnet. Der resultierende RGBA Wert wird im Shared
Memory Pu�er akkumuliert. Es folgen weitere Iterationen, bis die für ERT nötige Sättigung
des Sehstrahls erreicht ist oder das Volumen verlassen wird.
Weiterhin werden Register durch das Verbot von Inlining für die Funktionen zur Gradien-
tenberechnung und zum Shading eingespart, der Compiler nimmt dies sonst standardmäÿig
vor. Mehrfach verwendete Werte werden nicht zwischengespeichert, wenn die erneute Be-
rechnung schneller ist. double Typen werden nicht verwendet, auch auf int wird möglichst
verzichtet. float Werte sind bei vielen Operationen performanter und nie schlechter.
5 Ergebnisse
Wird der Kernel für eine CC unter 2.0 kompiliert, belegt er 38 Register. Wird das Inlining,
wie im vorigen Abschnitt berichtet, untersagt, ist der Compiler in der Lage, die Register-
belegung weiter zu optimieren. Unter Verwendung von 44 Byte Local Memory sinkt die
Anzahl benötigter Register so auf 32. Dadurch sind mehr Warps pro Thread Block bzw.
mehr aktive Thread Blocks auf einem MP möglich. Read-After-Write Kon�ikte von Regi-
stern und die Latenz von O�-Chip Speicherzugri�en können besser verdeckt werden. Wird
auf Shading verzichtet und bei der Sehstrahlintegration nur noch Emission und Absorption
berücksichtigt, werden pro Thread nur 14 Prozessorregister belegt.
Im weiteren Verlauf dieses Abschnitts werden Ergebnisse des Renderers dargestellt. Zur
Steigerung der Vergleichbarkeit werden Kon�gurationsparameter mit besonderem Ein�uss
angegeben. Abb. 3 zeigt mit Volt angefertigte Renderings. Alle in diesem Beitrag verwendeten
Datensätze sind bei [Röt06] erhältlich.
Abbildung 3: Renderings der Datensätze Bonsai1-HI, Engine und Porsche
Die Messungen werden mit zwei unterschiedlichen GPUs unter denselben Bedingungen
durchgeführt: einer GTX 280 (30 · 8 Kerne) (Abb. 5) und einer GTX 480 (15 · 32 Kerne)
(Abb. 6). In beiden Fällen wird dasselbe Kompilat für CC 1.2 verwendet. Die Performanz des
Kernels ist auf der GTX 480 mit einem CC 2.0 Kompilat schlechter, obwohl es sich um eine
Fermi GPU handelt. In den Messergebnissen werden die Frameraten für Kombinationen von
Ausgabegröÿen mit Thread Block Dimensionen angegeben. Die Gröÿen der Thread Blocks
sind paarweise so gewählt, dass 64 bzw. 256 Threads einen Block bilden. Im ersten Fall
können acht Thread Blocks auf einem MP mit 16384 Registern aktiv sein, im Letzten zwei,
wobei diese Gröÿe Read-After-Write Kon�ikte für CC unter 2.0 schon vollständig verdeckt.
Die drei Messreihen verwenden den Visible Male Datensatz mit unterschiedlichen 8 Bit
Abbildung 4: Renderings der Messungen mit dem VisMale Datensatz (von links nach rechts:
hohe, mittlere und keine Transparenz)
Transferfunktionen (Abb. 4). Zur Rauschunterdrückung blenden alle Transferfunktionen die
Werte [0, 40] aus. Bei der Einstellung hohe Transparenz besitzen die Werte [41, 255] die
Opazität 15, bei mittlere Transparenz 63 und bei keine Transparenz 255. Hier sei darauf
hingewiesen, dass die Transferfunktion Opazitätskorrektur auf Grundlage der Schrittweite
verwendet, die wiederum bezüglich der Voxelmaÿe normalisiert ist. Als Schrittweite wird 0.49
eingesetzt, wodurch auch die Opazität eines Samples gesenkt wird. An jedem Abtastpunkt
wird Shading berechnet, die entsprechende Schwelle ist deaktiviert. Die Strahlintegration
wird durch ERT bei Sättigungen über 95% abgebrochen.
Abbildung 5: FPS auf GTX 280 für hohe, mittlere und keine Transparenz
Abbildung 6: FPS auf GTX 480 für hohe, mittlere und keine Transparenz
6 Fazit
Die e�ziente Verwendung der GPU ermöglicht interaktives Volumenrendering durch klas-
sische Sehstrahlintegration. Dazu sind Details der CUDA Architektur und des Algorithmus
zu beachten. Für Berechnungen muss geprüft werden, ob sie auf dem Host oder dem De-
vice durchgeführt werden sollen. Die Betrachtung von Teilaufgaben ist dabei sinnvoll. Der
verwendete Bereich des Device Memory muss für die Aufgabe geeignet gewählt sein. Lässt
die Genauigkeit es zu, sollten auf dem Device intrinsische Funktionen verwendet werden.
Auf CUDA Vektortypen und dynamisch indexierte Arrays ist möglichst zu verzichten. Asyn-
chrone Kopieroperationen aktueller GPUs sind noch zu implementieren. Bei der Fermi Ar-
chitektur werden unregelmäÿige Zugri�e auf Global Memory durch L1 und L2 Caches unter-
stützt. Dies ist für räumliche Datenstrukturen nutzbar. Auf einer älteren Revision führte die
Implementierung eines Min/Max Octree mit Hilfe von Texturspeicher aufgrund zu häu�ger
abhängiger Leseoperationen und deutlich gestiegener Divergenz nicht zum Erfolg. Die Ver-
wendung eines Importance Volume zum adaptiven Sampling ist möglich. Zur Reduktion der
Banding Artefakte kann der O�set der Sehstrahlen gestreut werden. Mit mehrdimensionalen
Transferfunktionen und einem entsprechenden Editor können Benutzer mehr Informationen
aus einem Volumen extrahieren. Letztendlich ist die gewonnene Geschwindigkeit Ausgangs-
punkt zur Erprobung aufwändigerer Rekonstruktion, Beleuchtung und Schattierung.
Literatur
[CN94] Cullip, Timothy J. und Ulrich Neumann: Accelerating Volume Recon-
struction With 3D Texture Hardware. Technischer Bericht, Chapel Hill, NC,
USA, 1994.
[EKE01] Engel, Klaus, Martin Kraus und Thomas Ertl: High-quality pre-
integrated volume rendering using hardware-accelerated pixel shading. In:
HWWS '01: Proceedings of the ACM SIGGRAPH/EUROGRAPHICS workshop
on Graphics hardware, Seiten 9�16, New York, NY, USA, 2001. ACM.
[Jat10] Jato, Oliver: Fortgeschrittene Beschleunigung direkter Volumenvisualisierung
mit NVIDIA CUDA. Bachelor Thesis, Hochschule Bonn-Rhein-Sieg, Sankt Au-
gustin, 2010.
[KPH+03] Kniss, Joe, Simon Premoze, Charles Hansen, Peter Shirley und
Allen McPherson: A Model for Volume Lighting and Modeling. IEEE Trans-
actions on Visualization and Computer Graphics, 9(2):150�162, 2003.
[KW03] Krüger, Jens und Rüdiger Westermann: Acceleration Techniques for
GPU-based Volume Rendering. In: VIS '03: Proceedings of the 14th IEEE Vi-
sualization 2003 (VIS'03), Seiten 287�292, Washington, DC, USA, 2003. IEEE
Computer Society.
[MHE01] Magallón, Marcelo, Matthias Hopf und Thomas Ertl: Parallel Vol-
ume Rendering Using PC Graphics Hardware. In: Paci�c Conference on
Computer Graphics and Applications, Seiten 384�389, 2001.
[MHS08] Mar²álek, Luká², Armin Hauber und Philipp Slusallek: High-speed
volume ray casting with CUDA. In: Interactive Ray Tracing, 2008. RT 2008.
IEEE Symposium on, Seiten 185�185, Aug. 2008.
[MRH10] Mensmann, Jörg, Timo Ropinski und Klaus H. Hinrichs: An Advanced
Volume Raycasting Technique using GPU Stream Processing. In: GRAPP: In-
ternational Conference on Computer Graphics Theory and Applications, Seiten
190�198, Angers, 2010. INSTICC Press.
[MWMS07] Moloney, Brendan, Daniel Weiskopf, Torsten Möller und Magnus
Strengert: Scalable Sort-First Parallel Direct Volume Rendering with Dy-
namic Load Balancing. In: Eurographics Symposium on Parallel Graphics and
Visualization (EGPGV07), Seiten 45�52. Eurographics Association, 2007.
[PBMH02] Purcell, Timothy J., Ian Buck,William R. Mark und Pat Hanrahan:
Ray tracing on programmable graphics hardware. ACM Trans. Graph.,
21(3):703�712, 2002.
[RGW+03] Roettger, Stefan, Stefan Guthe, Daniel Weiskopf, Thomas Ertl
und Wolfgang Strasser: Smart hardware-accelerated volume rendering. In:
VISSYM '03: Proceedings of the symposium on Data visualisation 2003, Seiten
231�238, Aire-la-Ville, Switzerland, Switzerland, 2003. Eurographics Associa-
tion.
[Röt06] Röttger, Stefan: The Volume Library. Online, http://www9.informatik.uni-
erlangen.de/External/vollib, Abruf 14.6.2011, 2006.
[SSKE05] Stegmaier, Simon, Magnus Strengert, Thomas Klein und Thomas
Ertl: A Simple and Flexible Volume Rendering Framework for Graphics-
Hardware�based Raycasting. In: Proceedings of the International Workshop on
Volume Graphics '05, Seiten 187�195, 2005.
[WE98] Westermann, Rüdiger und Thomas Ertl: E�ciently using graphics hard-
ware in volume rendering applications. In: SIGGRAPH '98: Proceedings of the
25th annual conference on Computer graphics and interactive techniques, Seiten
169�177, New York, NY, USA, 1998. ACM.
[ZCC09] Zhao, Yue, Xiaoyu Cui und Ying Cheng: High-Performance and Real-Time
Volume Rendering in CUDA. In: Biomedical Engineering and Informatics, 2009.
BMEI '09. 2nd International Conference on, Seiten 1�4, Oct. 2009.