cb
我的主要问题是:最大的性能冲击发生在哪里?在使用MapUnmap更新缓冲区数据时,还是绑定cbuffers本身时?
目前,我正在为一个 "shader-wrapper "类在以下两种实现中做出选择。
class VertexShader
{
...
public:
Bind(context)
{
// Bind all 14 buffers at once
context->VSSetConstantBuffers(0, 14, &m_ppCBuffers[0]);
context->VSSetShader(pVS, nullptr, 0);
}
// Set the data for a buffer in a particular slot
SetData(slot, size, pData)
{
D3D11_MAPPED_SUBRESOURCE mappedBuffer = {};
context->Map(buffers[slot], 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedBuffer);
memcpy(mappedBuffer.pData, pData, size);
context->Unmap(buffers[slot], 0);
}
private:
ID3D11Buffer* buffers[14];
ID3D11VertexShader* pVS;
}
这种方法可以让着色器将所有的cbuffers绑定在一个14的批次中,如果着色器的cbuffers注册到b0、b1、b3,那么数组就会像-> [cbWiCTextureLoader for this project!
class VertexShader
{
...
public:
Bind(context)
{
// all the buffers bind themselves
for(auto cb : bufferMap)
cb->Bind(context);
context->VSSetShader(pVS, nullptr, 0);
}
// Set the data for a buffer with a particular ID
SetData(std::string, size, pData)
{
// table lookup into bufferMap, then Map/Unmap
}
private:
std::unordered_map<std::string, ConstantBuffer*> bufferMap;
ID3D11VertexShader* pVS;
}
我对如何在我正在做的一个非常基本的D3D11引擎中组织常量缓冲区有一些麻烦。我的主要问题是:最大的性能冲击发生在哪里?...
恒定缓冲区是Direct3D 10的一个主要功能,所以早在2007年的Gamefest上,就有一个关于这个主题的最佳演讲。
Windows to Reality: 在你的游戏中获得Direct3D 10图形的最大优势。最初的意图是让CBs按照更新频率来组织:比如一个CB用于 "每级 "的东西,另一个用于 "每帧 "的东西,另一个用于 "每个对象",另一个用于 "每个通道 "等等。因此,我们的假设是,如果你改变了一个CB的任何部分,你将上传整个事情。CPU和GPU之间的Bandwdith是这里的真正瓶颈。
为了使这种方法有效,你基本上需要将所有的着色器设置为使用相同的方案。这可能很难管理,特别是当许多现代材质系统是艺术驱动的时候。
CBs的另一种方法是像动态VB一样使用它们来提交粒子,你用短命的常量来填充它,提交工作,然后每一帧都重置这个东西。这种方法基本上是人们在很多情况下为DirectX 12所做的。问题是,如果没有更新部分CB的能力,就太慢了。DirectX 11.1中的 "部分恒定缓冲区更新和偏移 "可选功能就是一种让这个工作的方法。也就是说,这个功能在Windows 7上不支持,在新版本的Windows上是 "可选 "的,所以你必须支持两个代码路径才能使用它。TL;DR:
从技术上讲,你可以一次绑定很多CB,但关键是要让那些经常变化的CB保持小规模。同时假设对一个CB的任何改变都需要在每次改变它时将整个东西更新到GPU上。