HLSL:包装错误?

时间:2013-01-29 01:10:21

标签: c++ graphics hlsl

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

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传递给着色器时,两个维度都具有相同的值

1 个答案:

答案 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>