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打包成另一个块……只是修改了答案(因为我认为它更适合这里),以解释如何使用布局。