我使用以下布局传递一个常量缓冲区:
struct
{
float spread;
D2D1_POINT_2F dimension;
D2D1_POINT_2F dimension2;
} m_constants;
为了调试,dimension和dimension2具有相同的值。
在着色器中我有:
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_constants传递给着色器时,两个维度都具有相同的值
答案 0 :(得分:2)
默认情况下,常量缓冲区数据对齐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;
};
这是描述这一点的link。
因此,安排结构的更好方法是:
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编译器标志,但这将适用于您的程序中的每个结构(这并不总是令人满意)。在visual studio中转到项目属性 - > c / c ++ - >代码生成,然后您有“结构成员对齐”选项,您可以在其中设置它。
您也可以在hlsl端使用packoffset,但这意味着c ++布局需要匹配打包的hlsl(这意味着您在hlsl常量缓冲区中保持相同的顺序,但仍然需要修改c ++版本)。 / p>