C++ 包装错误?

C++ 包装错误?,c++,graphics,hlsl,C++,Graphics,Hlsl,我使用以下布局传入一个常量缓冲区: struct { float spread; D2D1_POINT_2F dimension; D2D1_POINT_2F dimension2; } m_constants; 为便于调试,维度和维度2的值相同 在着色器中,我有: cbuffer constants { float spread; float2 dimension; float2 dimension2; }; float4 main(

我使用以下布局传入一个常量缓冲区:

struct 
{
    float spread;
    D2D1_POINT_2F dimension;
    D2D1_POINT_2F dimension2;
} m_constants;
为便于调试,维度和维度2的值相同

在着色器中,我有:

cbuffer constants
{
    float spread;
    float2 dimension;
    float2 dimension2;
};

float4 main(
    float4 pos      : SV_POSITION,
    float4 posScene : SCENE_POSITION,
    float4 uv0      : TEXCOORD0
    ) : SV_Target
{
    float width = dimension.x;
    float height = dimension.y;
    float2 uv2 = float2(posScene.x / width, posScene.y / height);
    color.rgb = float3(uv2.xy,  0);
    return color;
}
理论上,这应该输出一个渐变,左下角为绿色,右上角为红色。确实如此。 但是,如果在着色器中,我有宽度和高度来使用dimension2。我得到一个水平梯度,从左边的绿色到右边的黄色


为什么呢?当我将m_常量传递给着色器时,这两个维度的值相同。默认情况下,常量缓冲区数据按16字节对齐,因此这意味着:

cbuffer constants
{
    float spread;
    float2 dimension;
    float2 dimension2;
};
将是

cbuffer constants
{
    float spread; // 4 bytes
    float2 dimension; // 4 + 8 = 12 bytes
    float dummy; //12+8 = 20, which means we cross 16 for dimension 2, hence a dummy 4 bytes element is added
    float2 dimension2;
};
下面是一个描述这一点的例子

因此,安排结构的更好方法是:

struct 
{
    D2D1_POINT_2F dimension;
    D2D1_POINT_2F dimension2;
    float spread;
} m_constants;
并相应地修改hlsl对应项:

cbuffer constants
{
    float2 dimension;
    float2 dimension2;
    float spread; // No more 16 bytes crossing problem
};

另一种方法,在C++的基础上,不修改初始布局,或者声明结构如下:

#pragma pack(push)
#pragma pack(16) 
struct 
{
    float spread;
    D2D1_POINT_2F dimension;
    D2D1_POINT_2F dimension2;     
} m_constants;
#pragma pack(pop)
这将强制结构对齐16个字节

您也可以使用/Zp16编译器标志,但这将应用于程序中的每个结构(这并不总是可取的)。在VisualStudio中,转到项目属性->c/c++->代码生成,然后可以选择“结构成员对齐”,从中可以进行设置


你也可以在HLSL侧使用PosikOffice,但是这意味着C++布局需要与打包的HLSL一个匹配(这意味着在HLSL常量缓冲区中保持相同的顺序,但仍然需要修改C++版本)。出于好奇,有没有一种方法可以保留第一个布局,但以某种方式使用packoffset来解决问题?还有,为什么第一个布局一开始就不起作用?您可能希望编译将spread和dimension打包成一个块,将dimension2打包成另一个块……只是修改了答案(因为我认为它更适合这里),以解释如何使用布局。