Seite 1 von 1

OpenGL und Speicherlayouts

Verfasst: 07.08.2012, 17:52
von kristof
Hallo zusammen,

ich bin momentan dabei die OpenGL API Aufrufe unter einem dünnen Wrapper zu verstecken, der im wesentlichen dafür sorgen soll, dass ich mir nicht andauernd Gedanken über das Speicherlayout meiner Vertex- und Texturdaten machen muss.

Ich verwende überall in meinem Programm eine eigene Vektorklasse, die etwa wie folgt aussieht:

Code: Alles auswählen

template<typename type, int n>
struct vec {
	type data[n];

	// Eine Ganze Menge Kontruktoren und Operatoren
};
Soweit ich weiss macht der C++ Standard allerdings keinerlei Aussagen darüber, wie diese Struktur im Speicher aussieht. Das heisst, ich kann nicht einfach ein Array von vec´s erzeugen und einen Zeiger darauf an glBufferData übergeben. Ist das soweit richtig?

Am liebsten würde ich sogar noch mehrere Vektoren gruppieren um Vertices zu bilden, die ich dann interleaved an OpenGL übergeben kann:

Code: Alles auswählen

struct vertex {
	vec<float,3> position;
	vec<unsigned char,4> color;
	// ...
};
Bleibt mir nichts anderes übrig, als die Daten kurz vor der Übergabe an OpenGL in ein Byte Array umzukopieren, sodass ich das Speicherlayout bestimmen kann?
Wie Löst ihr das, dass ihr im Programm elegant auf die Daten zugreifen könnt und OpenGL trotzdem ein definiertes Speicherlayout garantieren könnt?

Re: OpenGL und Speicherlayouts

Verfasst: 07.08.2012, 18:22
von Artificial Mind
1. http://glm.g-truc.net/ für Vektoren
2. Soweit ich weiß halten sich die "großen Compiler" an char ist byte-aligned, int/float ist 4-byte aligned. Wenn man nichts weiter zu einem struct schreibt, sollten die Daten also von oben nach unten im Speicher hintereinander liegen und wenn man nur ints/floats und 4 chars für Farben nutzt auch passend aneinander.

Sonst vielleicht das hier mal lesen: http://en.wikipedia.org/wiki/Data_structure_alignment

Re: OpenGL und Speicherlayouts

Verfasst: 07.08.2012, 18:32
von kristof
Danke. Soweit war mir das aber auch schon klar, dass die gängigen Compiler sich im alignement von structs sehr ähneln. Auch die von dir verlinkte glm nutzt das aus soweit ich das gesehen habe. Aber es muss doch einen eleganteren Weg geben, der nicht auf undefiniertem Verhalten beruht :-/

Re: OpenGL und Speicherlayouts

Verfasst: 07.08.2012, 18:36
von Artificial Mind

Code: Alles auswählen

#pragma pack(1)
Nicht standardisiert,dafür dokumentiert und well defined.

Re: OpenGL und Speicherlayouts

Verfasst: 08.08.2012, 01:48
von Jeason
kristof hat geschrieben:Das heisst, ich kann nicht einfach ein Array von vec´s erzeugen und einen Zeiger darauf an glBufferData übergeben. Ist das soweit richtig?
Also bei mir funktionierte das zumindest mit einem Color Struct und Textur Daten. Sprich ich konnte einfach ein Color Struct Array direkt an glTexImage2D als Zeiger übergeben.

Re: OpenGL und Speicherlayouts

Verfasst: 08.08.2012, 08:15
von Artificial Mind
Ja, das ist homogen genug, als das es funktioniert.
Wenn du aber in einem Vertex-Struct ein byte und dann ein float speicherst, dann sollte das Struct 8 byte groß sein, da der float 4-byte-aligned wird. Und das ist halt ein Problem, weil du in deiner Buffer-Deklaration wahrscheinlich 1 byte und 4 bytes mitt Stride von 5 bytes angibst.

Re: OpenGL und Speicherlayouts

Verfasst: 08.08.2012, 09:03
von kristof
Genau, das ist das Problem. Und theoretisch dürfte der Compiler auch alles 8-aligned, 3-aligned oder x-aligned im Speicher ablegen wenn er meint, dass das für die Zielplattform Sinn ergibt.
Aber ich denke, ich werde mich jetzt tatsächlich erstmal mit #pragma pack(1) zufrieden geben. Wenn allerdings noch jemand eine gute Idee hat, wäre ich sehr froh sie zu hören :)

Re: OpenGL und Speicherlayouts

Verfasst: 08.08.2012, 09:50
von Lynxeye
Erst mal vorneweg: alle zur Zeit gebräuchlichen Platformen (x64, PPC, ARM) fordern ein natural Alignment der Daten, das Alignment der Daten ist also immer >= Größe der eingesetzten Datentypen. Zusätzlich nimmt kein Compiler ein Padding am Anfang der Struktur vor, sondern richtet die Struktur komplett am natural Alignment des größten Datentyps innerhalb der Struktur aus.

Das heißt im Klartext, dass wenn du etwas Handarbeit investierst und die Elemente deiner Struktur vom größten zum kleinsten Datentyp sortierst, benötigt der Compiler auf keine Fall ein Padding einzufügen.

Die pack Attribute sind zwar auf ziemlich jedem Compiler in irgendeiner Form verfügbar haben aber den Nachteil, dass dadurch evtl das natural Alignment zerstört wird und der Prozessor somit unaligned auf die Daten zugreifen muss, was erheblich Performance fressen kann. Sie sollten daher nur eingesetzt werden, wenn die Optimierung durch händisches sortieren der Strukturelemente nicht möglich ist.

Re: OpenGL und Speicherlayouts

Verfasst: 09.08.2012, 18:50
von glassbear
Lynxeye hat geschrieben:Das heißt im Klartext, dass wenn du etwas Handarbeit investierst und die Elemente deiner Struktur vom größten zum kleinsten Datentyp sortierst, benötigt der Compiler auf keine Fall ein Padding einzufügen.
Das stimmt so nicht. Selbst mit der Groessen-Sortierung kann und wird der Compiler Padding am Ende hinzufuegen, zum Beispiel um das struct auf 64 Byte zu padden = 1 CPU Cache Line.
Schon mehrfach gesehen im GCC und hat mir dann meine SSE-Funktionen zerhauen :cry:

Re: OpenGL und Speicherlayouts

Verfasst: 10.08.2012, 12:23
von Lynxeye
glassbear hat geschrieben:
Lynxeye hat geschrieben:Das heißt im Klartext, dass wenn du etwas Handarbeit investierst und die Elemente deiner Struktur vom größten zum kleinsten Datentyp sortierst, benötigt der Compiler auf keine Fall ein Padding einzufügen.
Das stimmt so nicht. Selbst mit der Groessen-Sortierung kann und wird der Compiler Padding am Ende hinzufuegen, zum Beispiel um das struct auf 64 Byte zu padden = 1 CPU Cache Line.
Schon mehrfach gesehen im GCC und hat mir dann meine SSE-Funktionen zerhauen :cry:
Das ist allerdings äußeres Padding, nicht inneres. Bei Größensortierung der Strukturelemente wird nie Padding innerhalb der Struktur auftreten. Natürlich wird der Compiler bei mehreren Instanzen der Struktur im Speicher äußeres Padding hinzuzufügen um das natural Alignment sichzustellen. Mit Cachelines hat das eher weniger zu tun, es sei denn du forderst den Compiler explizit dazu auf. Das maximale äußere Padding ist zum sicherstellen des natural Alignments immer sizeof(Größtes_Element_der_Struktur)-1. Aber selbst das lässt sich mit ein wenig Handarbeit vermeiden, indem man selbst seine Struktur am Ende entsprechend padded und die Stride beim Auslesen anpasst.

Re: OpenGL und Speicherlayouts

Verfasst: 10.08.2012, 18:01
von glassbear
Von innen und aussen war oben nicht die Rede ;)

Re: OpenGL und Speicherlayouts

Verfasst: 10.08.2012, 22:16
von dot
Ich bin mir auch nicht sicher, was genau du mit dieser Unterscheidung zwischen "innerem" und "äußerem" Padding bezweckst. Ein struct hat eine bestimmte Größe, die muss per Definition in jedem Kontext gleich sein...