Du bist nicht angemeldet.

Werbeanzeige

stef

Treue Seele

  • »stef« ist der Autor dieses Themas

Beiträge: 241

Wohnort: Kassel

Beruf: Softwareentwickler

  • Private Nachricht senden

1

10.07.2012, 13:00

Schwächen von OpenGL?

Note by dot: Abgespalten von hier

Zitat



Damit disqualifizierst du mehr oder weniger OpenGL an sich schon von vorn herein. Auch wenn OpenGL eine objektorientierte API ist, so sorgt, zumindest meiner Erfahrung nach, das kaputte Objektmodell leider dafür, dass es praktisch unmöglich ist, OpenGL Objekte in herkömmlichen Klassen zu wrappen. Ich hab jedenfalls bis dato noch keine brauchbare Lösung gefunden. Wenn jemand eine kennt, so wäre ich sehr daran interessiert...


Nur mal so aus Interesse: Wo genau hast du da ein Problem ?
"In C++ it's harder to shoot yourself in the foot, but when you do, you blow off your whole leg." — Bjarne Stroustrup.

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »dot« (11.07.2012, 13:51)


David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

2

10.07.2012, 13:23

Nur mal so aus Interesse: Wo genau hast du da ein Problem ?


Schau dir z.B. mal den Fall für Texturen an. OpenGL führt Operationen immer auf die aktuell gebundene Textur aus. Willst du jetzt z.B. eine Textur mit Daten befüllen, dann wäre ein Möglicher Ansatz:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Texture
{
public:
  void update(...., const byte* data)
  {
    glBindTexture // !! wichtig !!
    /// ...
    glTexSubImage2D(...) // arbeitet auf EINEM texturobject, glBindTexture selektiert das korrekte
  }
};

Texture tex1, tex2;

tex1.update(...); 
/// Problem: wieso ist tex1 jetzt aktiv gebunden? wurde doch nur geupdated?


DirectX way:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
class Texture
{
public:
  void update(...., const byte* data)
  {
    m_D3DTexture->LockRect(...) // arbeitet auf DEM texturobject das mit der Instanz assoziiert wird
  }
};

Texture tex1, tex2;

tex1.update(...);
@D13_Dreinig

stef

Treue Seele

  • »stef« ist der Autor dieses Themas

Beiträge: 241

Wohnort: Kassel

Beruf: Softwareentwickler

  • Private Nachricht senden

3

10.07.2012, 13:43

Deshalb sollte man auch immer die Objecte die man nicht mehr benötigt aus dem Bind-Kontext entfernen ...

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Texture 
{ 
public: 
   void update(...., const byte* data) 
   { 
      glBindTexture // !! wichtig !! // 
      // ... 
      glTexSubImage2D(...) // arbeitet auf EINEM texturobject, glBindTexture selektiert das korrekte 
      // ... 
      glBindTexture(..., 0); // Das aktuell gebundene Objekt wird entfernt ! 
   } 
}; 

Texture tex1, tex2; 
tex1.update(...); /// Kein Problem mehr weil keine Textur gebunden
"In C++ it's harder to shoot yourself in the foot, but when you do, you blow off your whole leg." — Bjarne Stroustrup.

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

4

10.07.2012, 13:49

Zitat


// ...
glBindTexture(..., 0); // Das aktuell gebundene Objekt wird entfernt !


Was ist wenn aber wenn Textur A gebunden war und nach dem Update auf einmal keine Textur mehr gebunden ist? Du müsstest dir also erstmal merken was für eine Textur gerade aktiv war und diese dann erneut binden. Das ist alles nicht besonders Intuitiv und schreit quasi nach spanennden Debugsessions.
@D13_Dreinig

dot

Supermoderator

Beiträge: 9 833

Wohnort: Graz

  • Private Nachricht senden

5

10.07.2012, 13:52

Mein Problem ist unter anderem genau dieser Bind Kram. Damit ist es unmöglich, z.B. OpenGL Texturen effizient in eine Klasse zu wrappen, da es entweder einen komplizierten, globalen Mechanismus braucht, der tracked, welche Textur gerade aktiv is, oder du in jeder Methode einfach prinzipiell immer binden und unbinden musst, was unnötig ineffizient ist. Aber gut, daran scheitert's jetzt nicht, man kann auch gut ohne Texture Klasse im Sinne der OOP arbeiten, ein einfaches RAII Objekt reicht. Viel schlimmer find ich, dass das Texture Target ein globaler Zustand ist. Überleg dir mal, was das genau bedeutet. Das bedeutet, dass ich zwar Texturobjekte hab, aber wenn ich eines verwenden will, kann ich das nicht direkt tun, sondern muss erstmal die globale Variable, die auf das aktuelle Texturobjekt zeigt, setzen. Mir fehlen echt die Worte, um zu beschreiben, was ich davon halte...genau das meinte ich mit "kaputtem Objektmodell". Ich frag mich bis heute, wieso genau das in OpenGL damals so gelöst wurde, denn das hätte schon jeder normaldenkende C Programmierer vor 30 Jahren als abscheulich empfunden. Ich vermute, dass es einfach eine Folge irgendwelcher Details der Treiberarchitektur auf alten SGI Maschinen ist oder sowas. Noch viel mehr frag ich mich daher, wieso das immer noch nicht gefixed wurde...Multithreading kannst du mit so einem Design jedenfalls vergessen und die Bugs, die man sich damit einfangen kann, sind auch einmalig...und das alles sind absolut keine technischen Limits, sondern einfach nur bedingt durch diese kaputte API...

Dieser Beitrag wurde bereits 11 mal editiert, zuletzt von »dot« (10.07.2012, 14:23)


6

10.07.2012, 14:35

Macht es überhaupt Sinn, sich zu merken, welche Textur aktiv ist? Ich kann mir kaum vorstellen, dass innerhalb der API überhaupt nichts optimiert wird und alles direkt an den Treiber weitergereicht wird, müsste nicht diese Abfrage dann schon in BindTexture stattfinden? Dann könnte man ja einfach das Bind in jede Funktion packen und schon hätte man seine Kapselung ganz genauso wie in DX.
Lieber dumm fragen, als dumm bleiben!

Architekt

Community-Fossil

Beiträge: 2 490

Wohnort: Hamburg

Beruf: Student

  • Private Nachricht senden

7

10.07.2012, 14:38

Zitat


// ...
glBindTexture(..., 0); // Das aktuell gebundene Objekt wird entfernt !


Was ist wenn aber wenn Textur A gebunden war und nach dem Update auf einmal keine Textur mehr gebunden ist? Du müsstest dir also erstmal merken was für eine Textur gerade aktiv war und diese dann erneut binden. Das ist alles nicht besonders Intuitiv und schreit quasi nach spanennden Debugsessions.

Naja, wenn du es schon in einer Klasse kapselst kannst du ja direkt vor Ort dafür sorgen, finde ich jetzt nicht weiter dramatisch.
In der SFML wird das afaik so gemacht:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
GLuint GetCurrent() const {
    GLint current;

    glCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &current));

    return current;
}

void _ReBind(GLuint previous_texture) const {
    if (previous_texture != this._texture) {
        glCheck(glBindTexture(GL_TEXTURE_2D, previous_texture));
    }
}


Und dann z.B. beim Smooth setzen:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
const GLuint previous_texture = this.GetCurrent();

this.Bind();

const GLenum smooth = enable ? GL_LINEAR : GL_NEAREST;

glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, smooth));
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, smooth));

this._ReBind(previous_texture);
Der einfachste Weg eine Kopie zu entfernen ist sie zu löschen.
- Stephan Schmidt -

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

8

10.07.2012, 14:38

Macht es überhaupt Sinn, sich zu merken, welche Textur aktiv ist? Ich kann mir kaum vorstellen, dass innerhalb der API überhaupt nichts optimiert wird und alles direkt an den Treiber weitergereicht wird, müsste nicht diese Abfrage dann schon in BindTexture stattfinden? Dann könnte man ja einfach das Bind in jede Funktion packen und schon hätte man seine Kapselung ganz genauso wie in DX.


Es geht eher darum, dass man dadurch (ungewollt) einen globalen Zustand ändert.

Zitat


finde ich jetzt nicht weiter dramatisch.


Doch, das ist schon dramatisch. OpenGL zwingt dich durch das API Design quasi dazu. Das ist nicht nur unschön sondern auch Fehleranfällig. Dot hat ja noch ein/zwei weitere interessante Punkte genannt.
@D13_Dreinig

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »David_pb« (10.07.2012, 14:46)


Legend

Alter Hase

Beiträge: 737

Beruf: Softwareentwickler

  • Private Nachricht senden

9

10.07.2012, 14:39

Wenn das Programm, das OpenGL benutzt, "sauber" arbeitet und nicht ständig die selbe Textur immer und immer wieder neu setzt, wäre so eine Abfrage unnötiger Aufwand.
"Wir müssen uns auf unsere Kernkompetenzen konzentrieren!" - "Juhu, wir machen eine Farm auf!"

Netzwerkbibliothek von mir, C#, LGPL: https://sourceforge.net/projects/statetransmitt/

dot

Supermoderator

Beiträge: 9 833

Wohnort: Graz

  • Private Nachricht senden

10

10.07.2012, 14:53

Macht es überhaupt Sinn, sich zu merken, welche Textur aktiv ist? Ich kann mir kaum vorstellen, dass innerhalb der API überhaupt nichts optimiert wird und alles direkt an den Treiber weitergereicht wird, müsste nicht diese Abfrage dann schon in BindTexture stattfinden? Dann könnte man ja einfach das Bind in jede Funktion packen und schon hätte man seine Kapselung ganz genauso wie in DX.

Nein, macht es imo nicht. Ich verwend einfach keinen OOP Wrapper, sondern nur minimale RAII Objekte und direkte gl Calls.
Die API ist normalerweise direkt im Treiber implementiert, denn OpenGL ist keine Library, sondern nur eine Schnittstellenspezifikation. Abgesehen davon, kann man sich nicht drauf verlassen, dass dieser entsprechend optimiert. Und selbst wenn, so ist es immer noch unnötiger Overhead, der rein durch die API bedingt ist und durch nichts sonst. Und Multithreading bleibt weiterhin ein Problem. NVIDIA hat nicht umsonst eine Extension, um glBindBuffer() überhaupt zu eliminieren. Mit Vertex Array Objects gibt's nun zumindest für das auch in der Core API eine Lösung.

Zitat


// ...
glBindTexture(..., 0); // Das aktuell gebundene Objekt wird entfernt !


Was ist wenn aber wenn Textur A gebunden war und nach dem Update auf einmal keine Textur mehr gebunden ist? Du müsstest dir also erstmal merken was für eine Textur gerade aktiv war und diese dann erneut binden. Das ist alles nicht besonders Intuitiv und schreit quasi nach spanennden Debugsessions.

Naja, wenn du es schon in einer Klasse kapselst kannst du ja direkt vor Ort dafür sorgen, finde ich jetzt nicht weiter dramatisch.

Natürlich kann man das so "lösen". Der Punkt ist, dass man mit jeder derartigen Lösung zwangsweise unnötigen Overhead in Kauf nimmt...

Es geht eher darum, dass man dadurch (ungewollt) einen globalen Zustand ändert.

Exakt und das ist nicht nur eine unerschöpfliche Quelle für unglaublich lustige Bugs, sondern disqualifiziert die API von vornherein für Multithreading.

EDIT: Ok, natürlich ist Multithreading mit OpenGL, zumindest in gewissem Rahmen (asynchrones Ressourcenmanagement), möglich, allerdings imo sehr anstregend. Für multithreaded Rendering gibt's immer noch keine Lösung...

Wenn das Programm, das OpenGL benutzt, "sauber" arbeitet und nicht ständig die selbe Textur immer und immer wieder neu setzt, wäre so eine Abfrage unnötiger Aufwand.

Der Punkt ist, dass OpenGL eben nicht mit OOP im herkömmlichen Sinn kompatibel ist. Das ist aber gar nicht mein Hauptkritikpunkt, das imo wirklich große Problem, ist der globale Zustand, der hinter allem steckt...

Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von »dot« (10.07.2012, 15:04)


Werbeanzeige