刚开始我想通过常量缓存上传几个数据到着色器使用,却出现了数据错误,结果调试发现是ByteWidth 的问题。

我的刚开始的常量缓存结构体为:

struct SceneConstantBuffer { XMFLOAT4X4 mvp; // Model-view-projection (MVP) matrix. XMFLOAT3 lightPos; XMFLOAT3 viewPos; XMFLOAT3 color; };

着色器代码对应为:

cbuffer SceneConstantBuffer : register(b0) { float4x4 g_mWorldViewProj; float3 lightPos; float3 viewPos; float3 color; };

因为常量缓存需要256字节对齐,所以通过如下代码进行对齐:

const UINT constantBufferSize = (sizeof(SceneConstantBuffer) + 255) & ~255;

本以为数据可以正常传过去,可惜却并不是。通过RenderDoc调试发现,上传的数据不正确。

DirectX12里面常量缓存数据传输出错_缓存

通过数据可以看出来,问题出现在哪。viewPos以前的数据都是正常的,而我的viewPos的第一个数据不见了,第二个数据填充到了第一个数据,第三个数据填充到了第二个数据,color的第一个数据填充了我viewPos的第三个数据,而color的第三个数据填充到了第一个数据,后面两个都被0填充了。通过数据的分析可以看出来是ByteWidth的问题,通过​​官方文档​​的解释好像是数据都必须是16的整数倍数,言外之意就是数据是通过16的整数倍进行填充的。然后我就把常量缓存结构体改为:

​ struct SceneConstantBuffer { XMFLOAT4X4 mvp; // Model-view-projection (MVP) matrix. XMFLOAT4 lightPos; XMFLOAT4 viewPos; XMFLOAT4 color; };​

着色器对应代码:

​cbuffer SceneConstantBuffer : register(b0) { float4x4 g_mWorldViewProj; float4 lightPos; float4 viewPos; float4 color; };​

也就是我把数据从float3变为float4,也就是从12字节变为16字节。

最后通过RenderDoc调试查看数据为:

DirectX12里面常量缓存数据传输出错_上传_02

也就是正常把数据上传过去啦。

结论:HLSL将数据打包为4字节对齐,此外,它不允许数据跨16字节(即4个float的vector)的访问。