Compiler ignoriert #pragma pack



  • Hallo zusammen
    Ich habe folgende Struktur:

    // ******************************************** struct "Light" *******************************************
    // This struct describes a single light source. Be aware that no member of this structure must cross
    // a 128-Bit boundary, otherwise this structure cannot simply be copied to the GPU registers.
    // Author: Samuel Lörtscher
    // *******************************************************************************************************
    #pragma pack(push,16)
    struct Light{
    public:
     // --------------------------------------- public dynamic members ---------------------------------------
     Color    Color;        // color
     Vector3  Position;     // position vector
     Vector3  Direction;    // direction vector
     float32  Theta;        // inner cone angle
     float32  Phi;          // outer cone angle
     float32  Fallof;       // fallof
     float32  Attenuation0; // the first attenuation
     float32  Attenuation1; // the second attenuation
     float32  Attenuation2; // the third attenuation
     // ------------------------------------------------------------------------------------------------------
    };
    #pragma pack(pop)
    // *******************************************************************************************************
    

    Diese sollte doch nun 72Bytes gross sein? Tatsächlich ist sie aber nur 64Bytes gross, so als würde ich das pack nicht machen? Hat vielleicht jemand eine Idee, wie ich den Compiler (Visual Studio 2010) dazu zwingen kann, diese Struktur korrekt auszurichten?

    Mfg Samuel


  • Administrator

    Ishildur schrieb:

    Diese sollte doch nun 68Bytes gross sein? Tatsächlich ist sie aber nur 64Bytes gross, so als würde ich das pack nicht machen? Hat vielleicht jemand eine Idee, wie ich den Compiler (Visual Studio 2010) dazu zwingen kann, diese Struktur korrekt auszurichten?

    1. Ich nehme an, dass Color ein ARGB Wert ist mit 4x 32 Bit Zahlen.
    2. Ich nehme an, dass Vector3 eine Struktur mit 3x 32 Bit Zahlen ist.
    3. Dann wäre 64 Bytes für mich absolut in Ordnung. Wieso sollten es 68 Bytes sein, wenn es auf ein vielfaches von 16 Bytes packen sollen?

    Grüssli



  • @Dravere

    wenn es auf ein vielfaches von 16 Bytes packen sollen?

    Oje, in diesem Fall habe ich wohl packed falsch verstanden. Nein was ich brauche ist ein packing, bei welcher keine der Membervariablen eine 128bit Grenze überschreitet:

    struct Light{
    public:
     // --------------------------------------- public dynamic members ---------------------------------------
     Color    Color;        // --> neuer 128bit Bereich (0 padding)
     Vector3  Position;     // --> neuer 128bit Bereich (0 byte padding)
     Vector3  Direction;    // --> neuer 128bit Bereich (4 byte padding)
     float32  Theta;        // --> neuer 128bit Bereich (4 byte padding)
     float32  Phi;          // 
     float32  Fallof;       // 
     float32  Attenuation0; // 
     float32  Attenuation1; // --> neuer 128bit Bereich (0 padding)
     float32  Attenuation2; //
     // ------------------------------------------------------------------------------------------------------
    };
    

    Würde man bspw. nach Position kein padding von 1 byte machen, würde Direction anschliessend auf 2 128Bit Register der Grafikkarte verteilt und das ist nix gut!

    Weisst du, wie man sowas machen kann? Ich meine mir ist schon klar, dass ich einfach Bytes hineinpflastern kann, aber ich meine eine etwas elegantere Möglichkeit, also nicht

    struct A{
     Vector3 B;
     uint32   Padding0;
     Vector3 C;
     uint32   Padding1;
    };
    

    oder sowas

    P.S.
    Hier sieht man die Packing rules von HLSL http://msdn.microsoft.com/en-us/library/bb509632(v=VS.85).aspx
    Natürlich müssen meine C++ Strukturen identisch gepackt werden, damit ich sie in die Konstantenregistern der Vertex- und Pixelshader kopieren kann, ohne in jedem Frame das Ganze auseinanderfrickeln zu müssen...


  • Administrator

    Grundsätzlich so:

    #include <iostream>
    
    struct Color
    {
      float a, r, g, b;
    };
    
    struct Vector3
    {
      float x, y, z;
    };
    
    typedef float float32;
    
    struct Light
    {
      __declspec(align(16)) Color    Color;        // color
      __declspec(align(16)) Vector3  Position;     // position vector
      __declspec(align(16)) Vector3  Direction;    // direction vector
      __declspec(align(16)) float32  Theta;        // inner cone angle
      __declspec(align(16)) float32  Phi;          // outer cone angle
      __declspec(align(16)) float32  Fallof;       // fallof
      __declspec(align(16)) float32  Attenuation0; // the first attenuation
      __declspec(align(16)) float32  Attenuation1; // the second attenuation
      __declspec(align(16)) float32  Attenuation2; // the third attenuation
    };
    
    int main()
    {
      std::cout << sizeof(Light) << std::endl;
      std::cin.get();
    }
    

    Aber das wäre dann logischerweise eine Struktur mit 144 Bytes (9 x 16 Bytes).

    Grüssli



  • Du willst doch, dass die Vector3-Member deiner Struktur 16 statt 12 Bytes breit sind, wenn ich dich richtig verstanden habe. Das könntest du bei der Definition von Vector3 so erreichen:

    __declspec(align(16)) struct Vector3 {
      //...
    };
    

    EDIT: Ok, Dravere macht's besser. Ich wusste gar nicht, dass man das pro Member notieren kann (hab aber auch nur mal davon gelesen und es nie angewendet).



  • @Dravere
    Leider hast du mich noch nicht ganz verstanden 😉

    Theta, Phi, Fallof und Attenuation0 sollen nicht nach 128-bit ausgerichtet sein sondern nur Theta (sonst würde ja als Folge jeder einzelne Wert in einem separaten Register stehen (soviele Register habe ich gar nicht). Diese vier sollen in einem einzigen Register gepackt werden. Genauso wie Attenuation1 und Attenuation2.
    Wichtig ist auch dass jtzt nicht die erste Komponente von Direction in die letze Komponete des Registers gepackt wird, wo bereits Position drinn steht, sondern in einem neuen Register anfangen usw...



  • Ishildur schrieb:

    @Dravere
    Leider hast du mich noch nicht ganz verstanden 😉

    Theta, Phi, Fallof und Attenuation0 sollen nicht nach 128-bit ausgerichtet sein sondern nur Theta (sonst würde ja als Folge jeder einzelne Wert in einem separaten Register stehen (soviele Register habe ich gar nicht). Diese vier sollen in einem einzigen Register gepackt werden. Genauso wie Attenuation1 und Attenuation2.
    Wichtig ist auch dass jtzt nicht die erste Komponente von Direction in die letze Komponete des Registers gepackt wird, wo bereits Position drinn steht, sondern in einem neuen Register anfangen usw...

    Ja aber das erreichst du doch, wenn du nur die beiden Vector3-Member auf 16 Bytes ausrichtest (mit Däckelspeck... 😉 ).

    struct Light
    {
      Color    Color;        // color
      __declspec(align(16)) Vector3  Position;     // position vector
      __declspec(align(16)) Vector3  Direction;    // direction vector
      float32  Theta;        // inner cone angle
      float32  Phi;          // outer cone angle
      float32  Fallof;       // fallof
      float32  Attenuation0; // the first attenuation
      float32  Attenuation1; // the second attenuation
      float32  Attenuation2; // the third attenuation
    };
    

    Oder liege ich da falsch?


  • Administrator

    _matze schrieb:

    Oder liege ich da falsch?

    Hätte ich jetzt auch gesagt. Allerdings wird die Struktur dann 80 Bytes gross werden, weil er nochmals 8 Bytes ganz am Ende einfügt. Aber das sollte hoffentlich kein Problem darstellen.

    Grüssli


Anmelden zum Antworten