1

我正在传递一个具有以下布局的常量缓冲区:

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;
}

理论上,这应该输出一个渐变,左下角是绿色,右上角是红色。它确实如此。但是,如果在着色器中我有宽度和高度来使用维度 2。我得到一个从左边的绿色到右边的黄色的水平渐变。

这是为什么?当我将 m_constants 传递给着色器时,两个维度都具有相同的值

4

1 回答 1

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;
};

这是一个描述这一点的链接

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

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++ 版本)。

于 2013-01-29T20:56:57.523 回答