GLM, OpenGL, VBO, Struct Padding



  • Foxx90 schrieb:

    Inwiefern kann GLM das dann überhaupt beeinflussen ?

    Indem es eben das compilerspezifische Objektlayout berücksichtigt. Auch wenn der Standard im Allgemeinen vielleicht kein bestimmtes Layout garantiert, für die jeweiligen Compiler ist sehr gut dokumentiert, wie genau das Layout aussieht. Und im konkreten Fall gibt es da nicht wirklich viel zu berücksichtigen...

    Foxx90 schrieb:

    Und OpenGL WILL die Werte hintereinander haben. Der Stride Parameter würde voraussetzen, dass hinter jedem Wert ein bestimmtes Padding-Array/Byte ist, aber wie schon gesagt, das ist leider unvorhersehbar.

    Nicht unbedingt, über Stride und Offset kannst du die Daten interleaven

    Foxx90 schrieb:

    Insofern stimmte ich cooky451 voll zu (das war ja meine anfängliche Befürchtung), dass man hier nur mit Arrays am besten arbeiten sollte.

    Nun, mit Arrays hätte man sogar ein vom Standard garantiertes Layout. Aber wie gesagt, nur weil der Standard kein Layout garantiert, heißt das noch lange nicht, dass man nicht weiß, was der Compiler macht...

    Foxx90 schrieb:

    Und warum Interleaved ? Warum nicht mehrere VBOs + VAO ? Hat Interleaved einen Performancegewinn ? Wenn man das getrennt hält, müsste es ja einfacher sein, die Werte unabhängig von einander zu aktualisieren.

    Ja, Interleaved hat einen potentiellen Performancevoteil. Aber wenn du die Daten ständig updaten musst, dann werden getrennte VBOs bzw. separate Arrays natürlich wieder potentiell von Vorteil sein...

    EDIT: "Die Reihenfolge der Variablen ändern" darf der Compiler übrigens schon laut Standard nicht, zumindest wenn alle Variablen unter den gleichen access specifier fallen. Und im Falle von aufeinanderfolgenden floats wird kein mir bekannter x86 Compiler zwischen die Member Padding einbauen...



  • Da muss man nichts Compilerspezifisches beachten, wenn man es richtig macht.

    class vector3
    {
      float data_[3];
    };
    

    Ist standard layout, daher &vector3 == &data_[0], das Array liegt garantiert direkt hintereinander im Speicher, und mit stride bekommt man das Padding am Ende des structs weg.



  • Richtig, die glm Vektoren sehen aber nicht so aus, sondern eher so in der Richtung:

    struct vec3
    {
      union
      {
        struct
        {
          float x;
          float y;
          float z;
        };
    
        struct
        {
          float r;
          float g;
          float b;
        };
    
        ...
      };
    };
    

    Und da ist laut Standard (wenn man zunächst gleich mal ignoriert, dass der Standard anomye structs nicht kennt) afaik nur garantiert, dass x und r die gleiche Adresse haben und dass ein Pointer auf das struct auf x bzw. r zeigt...



  • Ich glaube, dass hier ist die entsprechende Stelle für vec4

    #	if(GLM_COMPONENT == GLM_COMPONENT_CXX11)
    		union 
    		{
    #		if(defined(GLM_SWIZZLE))
    			_GLM_SWIZZLE4_2_MEMBERS(value_type, glm::detail::tvec2<value_type>, x, y, z, w)
    			_GLM_SWIZZLE4_2_MEMBERS(value_type, glm::detail::tvec2<value_type>, r, g, b, a)
    			_GLM_SWIZZLE4_2_MEMBERS(value_type, glm::detail::tvec2<value_type>, s, t, p, q)
    			_GLM_SWIZZLE4_3_MEMBERS(value_type, glm::detail::tvec3<value_type>, x, y, z, w)
    			_GLM_SWIZZLE4_3_MEMBERS(value_type, glm::detail::tvec3<value_type>, r, g, b, a)
    			_GLM_SWIZZLE4_3_MEMBERS(value_type, glm::detail::tvec3<value_type>, s, t, p, q)
    			_GLM_SWIZZLE4_4_MEMBERS(value_type, glm::detail::tvec4<value_type>, x, y, z, w)
    			_GLM_SWIZZLE4_4_MEMBERS(value_type, glm::detail::tvec4<value_type>, r, g, b, a)
    			_GLM_SWIZZLE4_4_MEMBERS(value_type, glm::detail::tvec4<value_type>, s, t, p, q)
    #		endif//(defined(GLM_SWIZZLE))
    
    			struct{value_type r, g, b, a;};
    			struct{value_type s, t, p, q;};
    			struct{value_type x, y, z, w;};
    		};
    #	elif(GLM_COMPONENT == GLM_COMPONENT_CXX98)
    		union {value_type x, r, s;};
    		union {value_type y, g, t;};
    		union {value_type z, b, p;};
    		union {value_type w, a, q;};
    
    #		if(defined(GLM_SWIZZLE))
    			// Defines all he swizzle operator as functions
    			GLM_SWIZZLE_GEN_REF_FROM_VEC4(T, detail::tvec4, detail::tref2, detail::tref3, detail::tref4)
    			GLM_SWIZZLE_GEN_VEC_FROM_VEC4(T, detail::tvec4, detail::tvec2, detail::tvec3, detail::tvec4)
    #		endif//(defined(GLM_SWIZZLE))
    #	else //(GLM_COMPONENT == GLM_COMPONENT_ONLY_XYZW)
    		value_type x, y, z, w;
    
    #		if(defined(GLM_SWIZZLE))
    			// Defines all he swizzle operator as functions
    			GLM_SWIZZLE_GEN_REF_FROM_VEC4_COMP(T, detail::tvec4, detail::tref2, detail::tref3, detail::tref4, x, y, z, w)
    			GLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(T, detail::tvec4, detail::tvec2, detail::tvec3, detail::tvec4, x, y, z, w)
    #		endif//(defined(GLM_SWIZZLE))
    #	endif//GLM_COMPONENT
    


  • Kann es sein, dass wenn man eine Deklaration so macht:

    float x, y, z, w statt float x; float y; ... man vlt. dem Compiler "verbieten" Padding dazwischen zuschieben ?

    Ich rate nur, und hoffe innerlich 😛



  • Nein



  • Ja, das ist natürlich doof, warum machen die das so? Ist doch auch totaler Quatsch, meine Vektor Klasse sah irgendwie so aus

    template <typename T, std::size_t N>
    class vector
    {
      std::array<T, N> data_;
    };
    

    Genau genommen war's zwar nur eine Spezialisierung für eine Matrix, aber der Punkt ist, dass man so nicht alles doppelt schreiben muss. Kann ich nicht ganz nachvollziehen was glm da macht.



  • Weil sie die gleiche Schnittstelle wie GLSL bieten wollen. Und in GLSL kann ich nunmal z.B. mit .x, .y, .z auf die Elemente der Vektoren zugreifen. Wenn du einen Weg kennst, um das standardkonform umzusetzen, dann bin ich ganz Ohr, ich such seit Jahren nach so einem Weg...



  • Na ja, ich schreibe halt .x(), .y(), .z(). Dass das wirklich ganz genau so wie GLSL aussieht war mir allerdins nicht sonderlich wichtig. (Ist irgendwie auch kaum sinnvoll? Jeder weis was mit .x() gemeint ist.)
    Interessant ist nur noch ob man T x() und void x(T) hat, oder T& x() und const T& x().



  • Jo, damit hast du halt mehr Noise in der Syntax. Ich bevorzuge die Variante mit einzelnen floats. Schön wärs natürlich wenn der Standard ein Layout garantieren würde, aber wenn mir alle nötigen Compiler ein entsprechendes Layout garantieren, dann is das fast genau so gut...



  • dot schrieb:

    Jo, damit hast du halt mehr Noise in der Syntax.

    Also ob ich x oder x() schreibe, ist mir doch recht egal. Jedenfalls spare ich die ganzen Algorithmen 3 mal zu schreiben. Weiter hat man auch noch einen operator [], und so etwas wie xy(), xz(), ... wie in GLSL ist auch möglich. Ich sehe wirklich keinen Vorteil in einzelnen floats. Aber jedem das Seine. 😉



  • cooky451 schrieb:

    dot schrieb:

    Jo, damit hast du halt mehr Noise in der Syntax.

    Also ob ich x oder x() schreibe, ist mir doch recht egal.

    Ja, wenn ich nur ab und zu mal x schreiben würde, wär mir das auch egal. Aber sobald es um irgendwelche komplexeren Ausdrücke geht, also um die Praxis, dann nerven mich die () ziemlich, wär nicht so, dass ich's nicht ausprobiert hätt... 😉



  • #define X x()
    ..
    #define X x
    


  • Makros sind für mich für sowas keine Option... 😉


Anmelden zum Antworten