3
\$\begingroup\$

To expand from my previous question, I must add I can't correctly map my C++ structs to a corresponding cbuffer inside the pixel shader. When outputing random colors defined in the struct C++ side, it happens I get wrong results i.e. an XMFLOAT4(0,0,0,1.0) would give me a red color (?).

So here is a code sample :

__declspec(align(16)) struct SceneParams {
    bool DEAOEnabled;
    XMFLOAT4 DEAOColor;
    double DEAOPow;
    bool lightEnabled;
    XMFLOAT4 lightColor;
    XMFLOAT3 lightDirection;
    bool lightMultiply;
    double lightMultiplyFactor;
    bool ambiantLightEnabled;
    XMFLOAT4 ambiantLightColor;
    bool HSEnabled;
    int HSSpread;
    bool fogEnabled;
    XMFLOAT4 fogColor;
    double fogDistanceMax;
    bool glowEnabled;
    XMFLOAT4 glowColor;
    double glowRadius;
    XMFLOAT4 skyColor;
    bool skyBoxEnabled;
    //uniform sampler2D skyBoxTexture;
    int skyBoxScheme0; // top
    int skyBoxScheme1; // left
    int skyBoxScheme2; // front
    int skyBoxScheme3; // right
    int skyBoxScheme4; // back
    int skyBoxScheme5; // bottom
    int skyBoxRotate;
    double skyBoxRotateSpeed;
    XMFLOAT3 skyBoxRotateAround;
    bool orbitTrapsEnabled;
    int orbitTrapsId;
    XMFLOAT4 objectColor;

    SceneParams(
        bool DEAOEnabled,
        XMFLOAT4 DEAOColor,
        double DEAOPow,
        bool lightEnabled,
        XMFLOAT4 lightColor,
        XMFLOAT3 lightDirection,
        bool lightMultiply,
        double lightMultiplyFactor,
        bool ambiantLightEnabled,
        XMFLOAT4 ambiantLightColor,
        bool HSEnabled,
        int HSSpread,
        bool fogEnabled,
        XMFLOAT4 fogColor,
        double fogDistanceMax,
        bool glowEnabled,
        XMFLOAT4 glowColor,
        double glowRadius,
        XMFLOAT4 skyColor,
        bool skyBoxEnabled,
        //uniform sampler2D skyBoxTexture,
        int skyBoxScheme0, // top
        int skyBoxScheme1, // left
        int skyBoxScheme2, // front
        int skyBoxScheme3, // right
        int skyBoxScheme4, // back
        int skyBoxScheme5, // bottom
        int skyBoxRotate,
        double skyBoxRotateSpeed,
        XMFLOAT3 skyBoxRotateAround,
        bool orbitTrapsEnabled,
        int orbitTrapsId,
        XMFLOAT4 objectColor
        ) : DEAOEnabled{ DEAOEnabled }, DEAOColor{ DEAOColor }, DEAOPow{ DEAOPow }, lightEnabled{ lightEnabled }, lightColor{ lightColor }, lightDirection{ lightDirection },
        lightMultiply{ lightMultiply }, lightMultiplyFactor{ lightMultiplyFactor }, ambiantLightEnabled{ ambiantLightEnabled }, ambiantLightColor{ ambiantLightColor },
        HSEnabled{ HSEnabled }, HSSpread{ HSSpread }, fogEnabled{ fogEnabled }, fogColor{ fogColor }, fogDistanceMax{ fogDistanceMax }, glowEnabled{ glowEnabled },
        glowColor{ glowColor }, glowRadius{ glowRadius }, skyColor{ skyColor }, skyBoxEnabled{ skyBoxEnabled }, skyBoxScheme0{ skyBoxScheme0 },
        skyBoxScheme1{ skyBoxScheme1 }, skyBoxScheme2{ skyBoxScheme2 }, skyBoxScheme3{ skyBoxScheme3 }, skyBoxScheme4{ skyBoxScheme4 }, skyBoxScheme5{ skyBoxScheme5 },
        skyBoxRotate{ skyBoxRotate }, skyBoxRotateSpeed{ skyBoxRotateSpeed }, skyBoxRotateAround{ skyBoxRotateAround }, orbitTrapsEnabled{ orbitTrapsEnabled },
        orbitTrapsId{ orbitTrapsId }, objectColor{ objectColor } {}

    SceneParams() {}
};

...
// create a scene params object
...

constantBufferDesc.ByteWidth = sizeof(SceneParams);
hr = g_d3dDevice->CreateBuffer(&constantBufferDesc, nullptr, &g_d3dConstantBuffers[CB_Scene_Params]);
g_d3dDeviceContext->PSSetConstantBuffers(4, 1, &g_d3dConstantBuffers[CB_Scene_Params]);
g_d3dDeviceContext->UpdateSubresource(g_d3dConstantBuffers[CB_Scene_Params], 0, nullptr, &g_SceneParams, 0, 0);

With HLSL :

cbuffer sceneParams : register(b4) {
    bool DEAOEnabled;
    float4 DEAOColor;
    double DEAOPow;
    bool lightEnabled;
    float4 lightColor;
    float3 lightDirection;
    bool lightMultiply;
    double lightMultiplyFactor;
    bool ambiantLightEnabled;
    float4 ambiantLightColor;
    bool HSEnabled;
    int HSSpread;
    bool fogEnabled;
    float4 fogColor;
    double fogDistanceMax;
    bool glowEnabled;
    float4 glowColor;
    double glowRadius;
    float4 skyColor;
    bool skyBoxEnabled;
    //uniform sampler2D skyBoxTexture;
    int skyBoxScheme0; // top
    int skyBoxScheme1; // left
    int skyBoxScheme2; // front
    int skyBoxScheme3; // right
    int skyBoxScheme4; // back
    int skyBoxScheme5; // bottom
    int skyBoxRotate;
    double skyBoxRotateSpeed;
    float3 skyBoxRotateAround;
    bool orbitTrapsEnabled;
    int orbitTrapsId;
    float4 objectColor;
}

I changed my cbuffer floats to doubles to match the C++ struct but to no avail. What's wrong with the way I did the mapping ?


Additionnaly, here is a byte-size dump of the struct members :

std::cout << sizeof(p.DEAOEnabled) << std::endl;
std::cout << sizeof(p.DEAOColor) << std::endl;
std::cout << sizeof(p.DEAOPow) << std::endl;
std::cout << sizeof(p.lightEnabled) << std::endl;
std::cout << sizeof(p.lightColor) << std::endl;
std::cout << sizeof(p.lightDirection) << std::endl;
std::cout << sizeof(p.lightMultiply) << std::endl;
std::cout << sizeof(p.lightMultiplyFactor) << std::endl;
std::cout << sizeof(p.ambiantLightEnabled) << std::endl;
std::cout << sizeof(p.ambiantLightColor) << std::endl;
std::cout << sizeof(p.HSEnabled) << std::endl;
std::cout << sizeof(p.HSSpread) << std::endl;
std::cout << sizeof(p.fogEnabled) << std::endl;
std::cout << sizeof(p.fogColor) << std::endl;
std::cout << sizeof(p.fogDistanceMax) << std::endl;
std::cout << sizeof(p.glowEnabled) << std::endl;
std::cout << sizeof(p.glowColor) << std::endl;
std::cout << sizeof(p.glowRadius) << std::endl;
std::cout << sizeof(p.skyColor) << std::endl;
std::cout << sizeof(p.skyBoxEnabled) << std::endl;
std::cout << sizeof(p.skyBoxScheme[0]) << std::endl;
std::cout << sizeof(p.skyBoxScheme[1]) << std::endl;
std::cout << sizeof(p.skyBoxScheme[2]) << std::endl;
std::cout << sizeof(p.skyBoxScheme[3]) << std::endl;
std::cout << sizeof(p.skyBoxScheme[4]) << std::endl;
std::cout << sizeof(p.skyBoxScheme[5]) << std::endl;
std::cout << sizeof(p.skyBoxRotate) << std::endl;
std::cout << sizeof(p.skyBoxRotateSpeed) << std::endl;
std::cout << sizeof(p.skyBoxRotateAround) << std::endl;
std::cout << sizeof(p.orbitTrapsEnabled) << std::endl;
std::cout << sizeof(p.orbitTrapsId) << std::endl;
std::cout << sizeof(p.objectColor) << std::endl;

Which outputs :

1
16
8
1
16
12
1
8
1
16
1
4
1
16
8
1
16
8
16
1
4
4
4
4
4
4
1
8
12
1
4
16

Here is the compiler layout :

1>      +---
1>   0  | DEAOEnabled
1>      | <alignment member> (size=3)
1>   4  | XMFLOAT4 DEAOColor
1>      | <alignment member> (size=4)
1>  24  | DEAOPow
1>  32  | lightEnabled
1>      | <alignment member> (size=3)
1>  36  | XMFLOAT4 lightColor
1>  52  | XMFLOAT3 lightDirection
1>  64  | lightMultiply
1>      | <alignment member> (size=7)
1>  72  | lightMultiplyFactor
1>  80  | ambiantLightEnabled
1>      | <alignment member> (size=3)
1>  84  | XMFLOAT4 ambiantLightColor
1>  100 | HSEnabled
1>      | <alignment member> (size=3)
1>  104 | HSSpread
1>  108 | fogEnabled
1>      | <alignment member> (size=3)
1>  112 | XMFLOAT4 fogColor
1>  128 | fogDistanceMax
1>  136 | glowEnabled
1>      | <alignment member> (size=3)
1>  140 | XMFLOAT4 glowColor
1>      | <alignment member> (size=4)
1>  160 | glowRadius
1>  168 | XMFLOAT4 skyColor
1>  184 | skyBoxEnabled
1>      | <alignment member> (size=3)
1>  188 | skyBoxScheme0
1>  192 | skyBoxScheme1
1>  196 | skyBoxScheme2
1>  200 | skyBoxScheme3
1>  204 | skyBoxScheme4
1>  208 | skyBoxScheme5
1>  212 | skyBoxRotate
1>  216 | skyBoxRotateSpeed
1>  224 | XMFLOAT3 skyBoxRotateAround
1>  236 | orbitTrapsEnabled
1>      | <alignment member> (size=3)
1>  240 | orbitTrapsId
1>  244 | XMFLOAT4 objectColor
1>      | <alignment member> (size=4)
1>      +---
\$\endgroup\$
4
  • 1
    \$\begingroup\$ You may find /d1reportSingleClassLayout<name> a useful command-line switch if using VS. You can add it to your project options via the "Additional Compiler Options" section of the C++ properties of your project. Replace "<name>" with a type name (e.g., /d1reportSingleClassLayoutSceneParams) and compile; the compiler's interpretation of the class layout will be printed to the output window, including pad bytes. \$\endgroup\$
    – user1430
    Aug 13, 2015 at 15:12
  • \$\begingroup\$ I can't find this option (VS 2015 community). -all right it's under Command Line ... \$\endgroup\$
    – PinkTurtle
    Aug 13, 2015 at 15:29
  • \$\begingroup\$ It's "undocumented." \$\endgroup\$
    – user1430
    Aug 13, 2015 at 15:58
  • \$\begingroup\$ I passed a **ptrptr instead of *ptr to my UpdateSubresource() for pSrcData :/ Problem solved. :) \$\endgroup\$
    – PinkTurtle
    Aug 18, 2015 at 8:55

2 Answers 2

5
\$\begingroup\$

Non-array struct members for constant buffers in HLSL are packed on four byte offsets, as many as it can into 16-byte vectors. If a member would straddle a vector boundary, it starts a new vector.

You cannot achieve this with just an alignment and pack directive, you need to have explicit padding in your CPU-side structure to emulate the CB layout rules.

Laying your structure out by hand:

Legend:
[--]             4 bytes, bool/short/int/float
[------]         8 bytes, double/float2
[----------]     12 bytes, float3
[--------------] 16 bytes, float4, double2

0123456789abcdef
[--]             *- bool DEAOEnabled;
[--------------] *- XMFLOAT4 DEAOColor;
[------][--]     *- double DEAOPow;
                 \- bool lightEnabled;
[--------------] *- XMFLOAT4 lightColor;
[----------][--] *- XMFLOAT3 lightDirection;
                 \- bool lightMultiply;
[------][--]     *- double lightMultiplyFactor;
                 \- bool ambiantLightEnabled;
[--------------] *- XMFLOAT4 ambiantLightColor;
[--][--][--]     *- bool HSEnabled;
                 |- int HSSpread;
                 \- bool fogEnabled;
[--------------] *- XMFLOAT4 fogColor;
[------][--]     *- double fogDistanceMax;
                 \- bool glowEnabled;
[--------------] *- XMFLOAT4 glowColor;
[------]         *- double glowRadius;
[--------------] *- XMFLOAT4 skyColor;
[--][--][--][--] *- bool skyBoxEnabled;
                 |- int skyBoxScheme0; // top
                 |- int skyBoxScheme1; // left
                 \- int skyBoxScheme2; // front
[--][--][--][--] *- int skyBoxScheme3; // right
                 |- int skyBoxScheme4; // back
                 |- int skyBoxScheme5; // bottom
                 \- int skyBoxRotate;
[------]         *- double skyBoxRotateSpeed;
[----------][--] *- XMFLOAT3 skyBoxRotateAround;
                 \- bool orbitTrapsEnabled;
[--]             *- int orbitTrapsId;
[--------------] *- XMFLOAT4 objectColor;

We can see here that you have a lot of gaps in the canonical CB layout due to would-be straddling elements which you need to emulate on the CPU side.

\$\endgroup\$
3
  • \$\begingroup\$ Terrific answer =D Thanks a lot. So as an example, if I am @ position skyBoxRotateAround inside the cbuffer, defining float4 skyBoxRotateAround would give me the orbitTrapsEnabled value as skyBoxRotateAround.w ? I wonder why DX11 doesn't have an OpenGL glGetUniformLocation() similar methodology ? \$\endgroup\$
    – PinkTurtle
    Aug 13, 2015 at 15:58
  • \$\begingroup\$ @PinkTurtle In the original buffer definition, skyBoxRotateAround lives in cb[16].xyz and orbitTrapsEnabled would reside in cb[16].w. As the types differ and constant buffer contents go through no value translation, mapping in a float4 would result in a rather meaningless .w swizzle. \$\endgroup\$ Aug 13, 2015 at 16:04
  • \$\begingroup\$ Is cb[x] a valid syntax ? I guess not would be cool tho :| \$\endgroup\$
    – PinkTurtle
    Aug 13, 2015 at 16:23
0
\$\begingroup\$

I believe your DEAOColor crosses the 16 byte alignment boundary. Your first bool is 4 bytes so DEAOColor get's cut in two. Try switching them (and any other variable that doesn't fit within the 16 byte steps).

\$\endgroup\$
3
  • \$\begingroup\$ I thought __declspec(align(16)) would take care of that ? \$\endgroup\$
    – PinkTurtle
    Aug 13, 2015 at 14:43
  • \$\begingroup\$ I'm unsure but I don't think you can count on that when sending to video memory. You might need a padding variable as well, so the entire structure is a multiple of 16. \$\endgroup\$ Aug 13, 2015 at 14:52
  • \$\begingroup\$ The c++ structure is definitely a multiple of 16 - else the rendering would crash and the console output some complaining (happened to me before - D3D11 ERROR: ID3D11Device::CreateBuffer: The Dimensions are invalid. For ConstantBuffers, marked with the D3D11_BIND_CONSTANT_BUFFER BindFlag, the ByteWidth (value = xxx) must be a multiple of 16. [...]). \$\endgroup\$
    – PinkTurtle
    Aug 13, 2015 at 14:57

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .