Tutorial OpenGL3 Das Objekt System von OpenGL3: Unterschied zwischen den Versionen

Aus DGL Wiki
Wechseln zu: Navigation, Suche
(Die Seite wurde neu angelegt: „Seit OpenGL3 sind alle verwendbaren Daten in Objekten verpackt. Die OpenGL3 Bibliothek ist in c geschrieben und kennt daher keine Klassen, daher werden sogenannte…“)
 
Zeile 17: Zeile 17:
 
Durch eine Namenskonvention sind diese recht einfach zu erkennen.
 
Durch eine Namenskonvention sind diese recht einfach zu erkennen.
 
So werden alle Befehle, zum erzeugen der Objekte wie folgt aufgebaut.
 
So werden alle Befehle, zum erzeugen der Objekte wie folgt aufgebaut.
glGen[Objekttyp]s(Anzahl,Pointer auf ID-Array);
+
<source lang="cpp">glGen[Objekttyp]s(Anzahl,Pointer auf ID-Array);</source>
 
Als Beispiel folgendes:
 
Als Beispiel folgendes:
glGenTextures(1,&TextureID);
+
<source lang="cpp">glGenTextures(1,&TextureID);</source>
 
Die Zerstörung und das aktivieren eines Objektes wird auch über Namenskonventionen erleichtert.
 
Die Zerstörung und das aktivieren eines Objektes wird auch über Namenskonventionen erleichtert.
glBind[Objekttyp](...,ID);//Anzahl und Typ der Parameter sind Unterschiedlich.
+
<source lang="cpp">glBind[Objekttyp](...,ID);//Anzahl und Typ der Parameter sind Unterschiedlich.
glDelete[Objekttyp]s(Anzahl,Pointer auf ID-Array);
+
glDelete[Objekttyp]s(Anzahl,Pointer auf ID-Array);</source>
 
Als Beispiel folgendes:
 
Als Beispiel folgendes:
glBindTexture(GL_TEXTURE_2D,TextureID);
+
<source lang="cpp">glBindTexture(GL_TEXTURE_2D,TextureID);
glDeleteTexture(1,&TextureID);
+
glDeleteTexture(1,&TextureID);</source>
  
 
Sobald man ein Objekt, mit der zu den Objekttyp passenden Generierungs-Funktion erstellt, erhält man eine ID und diese kann man nun verwenden um z.B. ab zu fragen was das Objekt für ein Typ ist und ob es Aktiv ist.
 
Sobald man ein Objekt, mit der zu den Objekttyp passenden Generierungs-Funktion erstellt, erhält man eine ID und diese kann man nun verwenden um z.B. ab zu fragen was das Objekt für ein Typ ist und ob es Aktiv ist.
bool glIs[Objekttyp](ID);
+
<source lang="cpp">bool glIs[Objekttyp](ID);</source>
 
Als Beispiel folgendes:
 
Als Beispiel folgendes:
if (glIsTexture(TextureID))
+
<source lang="cpp">if (glIsTexture(TextureID))
 
{...}//Objekt ist eine Textur.
 
{...}//Objekt ist eine Textur.
 
else
 
else
{...}//Objekt ist keine Textur.
+
{...}//Objekt ist keine Textur.</source>
  
 
Wenn nun statt einer erhaltenen ID die 0 bei einer OpenGL Funktion übergeben wird, dann zeigt man also auf das Null-Objekt, welches bei allen Objekt-Bind Befehlen zufolge hat, dass dieser Buffertyp als deaktiviert gilt.
 
Wenn nun statt einer erhaltenen ID die 0 bei einer OpenGL Funktion übergeben wird, dann zeigt man also auf das Null-Objekt, welches bei allen Objekt-Bind Befehlen zufolge hat, dass dieser Buffertyp als deaktiviert gilt.
Zeile 39: Zeile 39:
  
 
Um das ein bischen zu festigen kommt nun mal ein kleines Beispiel.
 
Um das ein bischen zu festigen kommt nun mal ein kleines Beispiel.
//Erstellung
+
<source lang="cpp">//Erstellung
 
GLuint TextureID=0;
 
GLuint TextureID=0;
 
glGenTextures(1,&TextureID);//Es wird ein Objekt erzeugt und die ID dieses Objektes in die TextureID Variable geschrieben.
 
glGenTextures(1,&TextureID);//Es wird ein Objekt erzeugt und die ID dieses Objektes in die TextureID Variable geschrieben.
Zeile 55: Zeile 55:
 
//...
 
//...
 
//Aufräumen
 
//Aufräumen
glDeleteTextures(1,&TextureID);
+
glDeleteTextures(1,&TextureID);</source>
  
 
Ein Objekt bleibt solange Aktiv und/oder gebunden, bis ein anderes gebunden bzw. der Objektyp deaktiviert wurde.
 
Ein Objekt bleibt solange Aktiv und/oder gebunden, bis ein anderes gebunden bzw. der Objektyp deaktiviert wurde.

Version vom 14. August 2009, 16:03 Uhr

Seit OpenGL3 sind alle verwendbaren Daten in Objekten verpackt. Die OpenGL3 Bibliothek ist in c geschrieben und kennt daher keine Klassen, daher werden sogenannte ID's zur Assoziation verwendet. Wenn man also eine der Funktionen aufruft, die zur Erstellung eines Objektes zuständig ist, dann bekommt man eine 32Bit große, Vorzeichenlose Nummer zurück. Diese sind nicht zwingend aufsteigend Nummeriert, sondern können vom Treiber frei gewählt werden. Die einzige Bedingung die gestellt wird, ist das die ID 0 nicht vergeben wird, denn diese wird vom Treiber automatisch am Start reserviert und ein Null-Objekt erzeugt. Die Verwendung von Objekten Teilt sich in 4 Bereiche, Erstellung, Verändern, Verwenden und Vernichtung. Da es verschiedene Typen von Objekten gibt, müssen diese auch Unterschieden werden können und unterschiedlich anwendbar sein. Es gibt in OpenGL3 folgende Objekte:

  • Buffer(auch als VBO bekannt)
  • VertexArray
  • Query
  • Textur
  • FrameBuffer(auch als FBO bekannt)
  • Shader
  • Program

Für jeden Objekttyp gibt es eigene Funktionssammlungen für die 4 oben erwähnten Bereiche. Durch eine Namenskonvention sind diese recht einfach zu erkennen. So werden alle Befehle, zum erzeugen der Objekte wie folgt aufgebaut.

glGen[Objekttyp]s(Anzahl,Pointer auf ID-Array);

Als Beispiel folgendes:

glGenTextures(1,&TextureID);

Die Zerstörung und das aktivieren eines Objektes wird auch über Namenskonventionen erleichtert.

glBind[Objekttyp](...,ID);//Anzahl und Typ der Parameter sind Unterschiedlich.
glDelete[Objekttyp]s(Anzahl,Pointer auf ID-Array);

Als Beispiel folgendes:

glBindTexture(GL_TEXTURE_2D,TextureID);
glDeleteTexture(1,&TextureID);

Sobald man ein Objekt, mit der zu den Objekttyp passenden Generierungs-Funktion erstellt, erhält man eine ID und diese kann man nun verwenden um z.B. ab zu fragen was das Objekt für ein Typ ist und ob es Aktiv ist.

bool glIs[Objekttyp](ID);

Als Beispiel folgendes:

if (glIsTexture(TextureID))
{...}//Objekt ist eine Textur.
else
{...}//Objekt ist keine Textur.

Wenn nun statt einer erhaltenen ID die 0 bei einer OpenGL Funktion übergeben wird, dann zeigt man also auf das Null-Objekt, welches bei allen Objekt-Bind Befehlen zufolge hat, dass dieser Buffertyp als deaktiviert gilt. Möchte man z.B. FrameBuffer abschalten, weil man diesen nicht mehr braucht, dann benutzt man den passenden Bind Befehl und setzt als ID die 0 ein.

Um das ein bischen zu festigen kommt nun mal ein kleines Beispiel.

//Erstellung
GLuint TextureID=0;
glGenTextures(1,&TextureID);//Es wird ein Objekt erzeugt und die ID dieses Objektes in die TextureID Variable geschrieben.
//Weise Daten dem Objekt zu.
//...
//Zeichenroutine(Verwendung)
if (glIsTexture(TextureID))
{
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D,TextureID);//Bindet das Objekt als OpenGL 2D-Textur.
  //...
  glBindTexture(GL_TEXTURE_2D,0);
  glDisable(GL_TEXTURE_2D);
}
//...
//Aufräumen
glDeleteTextures(1,&TextureID);

Ein Objekt bleibt solange Aktiv und/oder gebunden, bis ein anderes gebunden bzw. der Objektyp deaktiviert wurde. Durch das ständige Binden,Aktivieren und Deaktivieren geht sehr viel Zeit verloren, die sich auf die Programmgeschwindigkeit auswirkt. OpenGL war Ursprünglich eine Statemachiene, also etwas galt solange, bis es verändert wurden, dann galt der neue Zustand. Dieses ist in OpenGL3 immer noch der Fall, allerdings in einer wesentlich abgeschwächten Form, da die meisten States schon entfernt werden konnten. Das gleiche System findet auch bei der Objektverwaltung seinen Platz, was heute allerdings wenig Sinn macht. Früher hat man beim Binden eine Hashtable verwendet, um aus der ID die dazugehörige Speicheradresse, der Objektdaten, auf im VideoRam zu ermitteln und im entsprechendem Globalen Variable zu setzen. Dies hat die Leistung in den früheren OpenGL Versionen erhöht, da die Art, wie man gezeichnet hat eine ganz andere war, als wie heute. Durch die generischen Buffer und der vom Entwickler bestimmten Shaderpipeline ist dieses ständige Binden zu dem Flaschenhals in der OpenGL3 Programmierung geworden. Die ID's, die man von OpenGL bekommt sind allerdings nur 32Bit groß und die Speicheraddressen, passen nicht in die 32Bit. Deshalb ist es bis jetzt noch nicht möglich, über die gegebene API das Problem zu lösen. Man müsste also mit jeder Speicherbus Erweiterung, die eine Grafikkarte mit sich bringt, auch die API anpassen, was etwas Aufwand ist. Der Grafikkartenhersteller Nvidia hat allerdings eine Erweiterung für OpenGL2 und Aufwärts zur verfügung gestellt, welche erlaubt die Speicheraddressen von den OpenGL Objekten ab zu fragen und diese in einen BuffeObjekt zu hinterlegen. Wenn man nun alle logisch zusammengehörenden Objektaddressen in jeweils einen Buffer hinterlegt, dann kann man mit Hilfe dieses alle Bind Befehle auf einen einzigen reduzieren und somit den Flaschenhals auf ein anderen Bereich verschieben. Dies ist allerdings noch eine Extension, wird aber wohl aufgrund seiner Einfachheit recht schnell in die ARB und dann in den OpenGL-Kern finden. Bis dahin muss der Programmierer versuchen das Problem so stark wie möglich zu reduzieren.

Wie schon erwähnt, ist OpenGL3 immer noch Statebasiert, was man sich zu nutze machen kann. Wenn man z.B. alle genutzen Daten nach bestimmten Kriterien sortiert, kann man somit die Anzahl der Bindings und Stateänderungen reduzieren. Im Laufe der einzelnen Artikel wird man noch die ein oder andere Möglichkeit sehen, weitere Optimierungen vor zu nehmen.