IRIS PERFORMER
Robert Wimberger
1. Einleitung
Der IRIS Performer wurde 1994 von Silicon Graphics entwickelt. Er stellt ein Entwicklungstoolkit dar, das es dem Programmierer ermöglicht, relativ einfach Graphiksoftware, wie realtime Graphikanwendungen, Simulationsvisualisierungen oder andere 3D Graphikanwendungen, zu erstellen. Basierend auf der Graphikbibliothek IRIS GL (OpenGL) stellt er zwei weitere Bibliotheken zur Verfügung. Einerseits die ‘low-level’-Library libpr, andereseits die ‘high-level’-Library libpf. Die Abbildung 1 zeigt den schematischen Aufbau einer Applikation unter Verwendung der Performer-Libraries.
Abb. 1 - Schematischer Aufbau
Im Prinzip fungiert libpr als Basisbibliothek des Performertoolkits. Sie stellt dem Anwender Funktionen zum effektiveren Rendering, wie optimierte Graphikprimitive oder auch shared memory utilities als Basis für Mehrprozessoranwendungen, zur Verfügung. Der zweite Level des Performers ist die Bibliothek libpf. Sie nutzt die Funktionen der libpr und erweitert sie um hierarchische Datenstrukturen, Mehrprozessorfunktionen und Features für real-time Anwendungen. Je nach Bedarf kann der Programmierer entscheiden, welche Bibliothek er für seine Anwendung benötigt.
2. libpr - Efficient Rendering
Sie stellt die Grundlage der high-performance Eigenschaften des Performers dar.
2.1. pfGeoset - Efficient Geometry Primitive
Datenstrukturen die verwendet werden um Geometriedaten zu repräsentieren und der Code der diese Daten an die Graphikhardware schickt, können sind oft ausschlaggebend für das Erreichen einer höheren Performance. pfGeoSet verwendet optimierte Renderingloops um das CPU-bottleneck zu vermeiden. Der Grundgedanke von pfGeoset ist, eine maximale immediate-mode Performance bei 3D-Geometrien zu erreichen. Im sogenannten immediate-mode muß die Host-CPU das Graphiksubsystem mit Primitiven, Vektoren und Attributkommandos füttern. Die Alternative zum immediate-mode stellen die Displaylisten dar. Sie setzen eine Liste von Kommandos in eine Datenstruktur um und schicken diese sehr effizient an das Graphiksubsystem. Aber die Verwendung von Displaylisten hat einige entscheidende Nachteile:
2.1.1. Funktionen von pfGeoSet
pfGeoSet ist eine Sammlung von Graphikprimitiven eines bestimmten Typs definiert durch:
Abb. 2 - pfGeoSet
Ein wesentlicher Punkt bei immediate-mode Applikationen ist, daß der Datentransfer zur Graphikhardware effizient ist, sonst sinkt die Performance der Anwendung drastisch. Die Verwendung von pfGeoState untertützt diese Anforderung, indem sie die Geometriedaten a priori nach Typ sortiert und dadurch extrem kurze Renderingschleifen erzeugt. Besteht eine pfGeoState-Struktur z.B. aus 2 Dreiecken, deren Farbe pro Dreieck definiert ist (siehe Abbildung 2), so verschwendet die entsprechende Renderingroutine keine Zeit damit, zu überprüfen, ob eine Farbe pro Punkt gerendert werden soll. Da pfGeoSet`s einen ziemlich großen Overhead besitzen - vorallem bei pfGeoSets mit sehr wenigen Primitiven - empfiehlt es sich Dreiecke in Meshes zusammenzufassen, um den Datendurchsatz zur Hardware zu erhöhen. Der pfuBuilder unterstützt den Anwender dabei, Polygone in Dreiecksverbunde (trianglemesh) zu zerlegen.
2.2. Efficient Graphics State Management
Mit Hilfe der Statuskommandos werden spezielle Attribute gesetzt, wie z.B. eine Änderung des Schattierungsmodelles oder es werden Texturen zugewiesen. Diese Kommandos verändern nicht direkt den Framebuffer, sondern versetzen die Hardware in spezielle Modi, die für eine optimierte Graphikausgabe notwendig sind. In der Library libpr stehen dem Anwender 3 Möglichkeiten zur Verfügung, um einen bestimmten Graphikstatus zu setzen. Jeder Graphikstatus hat spezielle Performancevorteile.
Für gewöhnlich wird der immediate mode verwendet, um globale Statusvariablen, wie Nebel, zu setzen. Der encapsulated mode ist zur Erstellungszeit für das Erscheinungsbild der Geometriedaten der Datenstruktur zuständig. Der Display List Mode wird hauptsächlich in Verbindung mit der Library libpf verwendet, um die Mehrprozessorunterstützung zu ermöglichen.
2.2.1 pfState - Immediate mode
pfState kann im wesentlichen in zwei Kategorien unterteilt werden :
wobei Modi (meist einfache Integerwerte) gesetzt und Attribute zugewiesen werden. Mit dem Befehl psShadeModel() wird das Schattierungsmodell gesetzt, oder pfApplyTex() weist eine Textur zu. PfState enthält den Zustand der aktuellen Datenstruktur in einem Stack auf den mit Push und Pop zugegriffen werden kann, um Zustände zu speichern oder wiederherzustellen. An der Spitze des Stacks befindet sich der aktuelle Zustand eines OpenGL-Fensters, welches der Performeranwendung zu Grunde liegt.
Beispiel:
Weiters werden Befehle wie pfInitState(), pfNewState() usw. zur Verfügung gestellt.
2.2.2. pfDispList - Display List mode
pfDispList unterscheidet sich von der normalen ‘OpenGL’ Displayliste, die nur auf libpr-Objekte referenziert. Sie isteditierbar und auch erweiterbar, kann aber auch Callbackfunktionen für anwenderspezifische Renderingfunktionen enthalten. Mit Hilfe von pfDispList’s können zwei Prozesse miteinander kommunizieren, wobei ein producer-Prozess die Liste füllt und ein sogenannter consumer-Prozeß die Liste abarbeitet und am Bildschirm darstellt. Dadurch kann der Datendurchsatz deutlich erhöht werden. pfDispLists können als FIFO- oder als Ringbuffer definiert werden, wobei producer- und consumer-Prozess gleichzeitig auf die Displaylist zugreifen können (read/write). Der Befehl pfNewDList() zum Beispiel, erzeugt eine neue Displaylist und der Befehl pfOpenDList() wählt eine bestimmte Displaylist aus.
2.2.3. pfGeoState - Encapsulated mode
pfGeoState stellt eine Möglichkeit dar um State`s in logischen Einheiten zu kombinieren. Man kann zum Beispiel Licht, eine ziegelartige Textur und ein orangefarbenes Material in einem pfGeoState setzen und es später bei Bedarf einer Geometrie zugeweisen. Ein pfGeoState kann mit einem pfGeoSet verknüpft sein, und so gemeinsam die Geometrie mit einem speziellen Aussehen definieren. Der Renderingstatus oder die Attribute von pfGeoStat können auf 2 Arten definiert sein:
Wenn alle Stateelemente lokal gesetzt sind, so entspricht pfGeoState einem vollständigen Graphikkontext. Es ist in den meisten Fällen sinnvoll, alle State’s auf pfGeoStateebene zu definieren. Manchmal ist es jedoch nützlich, State’s von den globalen Defaultstates zu erben und nur diejenigen explizit zu setzen, deren Wert sich oft ändert. Sinnvolle Beispiele für global gesetzte Werte sind Lichter, Nebel und Transparenz (normalerweise OFF). Materialien und Texturen werden lokal gesetzt.
3. libpf - Visual Simulation Library
libpf ist die Entwicklungslibrary von IRIS Performer, die all jene Funktionen zur Verfügung stellt, um eine effiziente Visualisierung zu ermöglichen. Features von libpf sind unter anderem hierarchische Datenstrukturen, Multiprozessing aber auch Importieren anderer Datenformate (z.B. Autodesk DXF).
3.1. Hierarchische Datenstrukturen
Graphische Szenerien können im Performer hierarchisch aufgebaut werden. Graphische Zustände (states) können daher von oben nach unten vererbt werden. Zusätzlich können sogenannte bounding volumes an jeden Knoten der Datenstruktur vergeben werden. Diese erhöhen die Performance bei Intersection- bzw. Cullingtests. Außerdem werden diese bei einer Änderung der Szenerie bzw. Datenstruktur automatisch geändert.
3.1.1. Traversals
Unter Traversals versteht man jene Operationen die für das Durchlaufen (traversieren) einer Datenbank zur Verfügung stehen. Der Performer kennt 3 verschiedene Traversalarten:
Die Visualisierung besteht aus den 2 Basistraversals: Culling und Drawing. Beim Culling wird die Datenstruktur durchlaufen, alle nicht sichtbaren Elemente werden eliminiert und es wird eine entsprechende Displayliste generiert. Anschließend arbeitet die Drawingtraversal die Displayliste ab und sendet Renderingkommandos an das Graphiksystem. Werden diese beiden Traversals einmal gesetzt, so werden sie immer automatisch aufgerufen und durchlaufen. Die Intersectiontraversals hingegen, sind benutzergesteuert. Sie untersuchen die Datenstruktur auf eventuelle Verschneidungen von Graphikelementen, wie z.B.: Kollisionserkennung. Zusätzlich können auch Callbackroutinen bei bestimmten Ereignissen den Intersectiontraversals eingefügt werden.
3.2. Multiprocessing
Der Performer bietet eine einfache Möglichkeit, mehrprozessorientierte Anwendungen zu erstellen. Dabei wird es vermieden, den Programmierer mit der Komplexität der Thematik zu belasten. Eine sogenannte Rendering-Pipeline (pfPipe), die in 3 Abschnitte unterteilt ist, übernimmt die Aufgabe, das Multiprocessing zu managen. Durch diese Unterteilung wird es den einzelnen Prozessen möglich, jeweils an einer bestimmten Stufe der Pipeline zu arbeiten.
3.2.1. pfPipe
pfPipes sind sogenannte Renderingpipelines. Jede Renderingpipeline rendert durch eine, mit ihr assoziierte, Graphikpipeline in ein OpenGL-Window. Die Anzahl der möglichen Pipelines hängt von der verwendeten Hardware ab.
Die 3 Stufen einer Renderingpipeline:
Jede dieser Stufen kann entweder in einem einzigen Prozeß kombiniert werden, oder in mehrere Prozesse (pfMultiprocess) unterteilt werden.
3.2.2. pfChannel
Ein Channel repräsentiert im Performer einen unabhängigen Blickpunkt in eine graphische Datenstruktur. Im Normalfall verwendet man einen einzigen Channel (siehe Abbildung 3)
Abb. 3 - Singlechannel
Abb. 4 - Multichannel
In Abbildung 4 wird die Verwendung von mehreren Channels veranschaulicht. Dieses wird dann verwendet, wenn man z.B. in einem Image ein weiteres Image erzeugen will. (z.B. Bei einem Fahrsimulator das Image, welches im Rückspiegel des Autos erscheinen würde).
3.3. Performance Optimierung
Der Performer stellt dem Anwender Funktionen zur Verfügung um seine Applikation zu tunen, wie level-of-detail switching, Transformationen eliminieren oder auch Billboard Geometry.
3.3.1. level-of-detail (pfLOD)
Um einen sinnlosen Aufwand an Rendering zu verhindern (ein sehr kleines Polygon, das sich weit vom Betrachtungspunkt befindet, muß nicht mit derselben Renderinggenauigkeit berechnet werden, wie ein großes Polygon mit kurzem Abstand zum Betrachter), ist es möglich den level-of-detail herunterzusetzen. Dazu werden unter anderem der Abstand vom Blickpunkt oder auch die Pixelgröße zur Selektion herangezogen.
3.3.2. Transformationen eliminieren (pfFlatten)
Während des Renderingprozesses benötigt man für Transformationen den Hardwarestack. Zuerst muß er gespeichert (push) werden, dann muß die Geometrie gezeichnet werden und zum Schluß muß der Hardwarestack wieder geladen (pop) werden. Diese Prozedur ist mitunter für kleine Objekte genauso aufwendig wie für große. pfFlatten erhöht die Performance auf Kosten des Speicherbedarfes, indem es die statische Geometrie kopiert, die aktuellen statischen Transformationen übernimmt und alle statischen Koordinatensysteme mit der Einheitsmatrix ersetzt.
3.3.3. Billboarded Geometry (pfBillboard)
Mit pfBillboard nutzt man den Umstand, daß manche symmetrische Objekte, wie Bäume, Wolken, Feuer etc. immer dem Beobachter zugewandt sind. Solche Objekte können durch sogenannte 2-dimensionale Billboardgraphics ersetzt werden. Rotationen um eine Achse oder einen Punkt sind auch bei Billboardgraphiken verfügbar, benötigen aber nicht den normalen Berechnungsaufwand, was die Performance bei Anwendungen erheblich erhöhen kann.
3.4. Importieren andere Datenformate
Eine weitere Library (libpfdb) steht unter dem Performer zur Verfügung. Mit Hilfe dieser Library kann man verschiedene Dateiformate anderer Hersteller lesen und in eine interne Performerdatenstruktur umwandeln. Es stehen sehr viele Datenformate zur Verfügung. Die meisten liegen in Sourcecodeform vor und können daher vom Programmierer selbst für eigene Datenformate adaptiert oder umprogrammiert werden. So stehen zum Beispiel Loader für AutoCAD DXF, Wavefront OBJ, Silicon Graphics Open Inventor und viele mehr zur Verfügung.
3.5. Weitere Features von libpf
libpf ermöglicht es weiters, real-time Applikationen durch Setzen konstanter Bildwiederholungsraten und Synchronisierung der Videoraten, zu erstellen. Ebenso stehen Funktionen zum Morphen zur Verfügung.
4. Literaturquellen