在DX9时代,很多渲染瓶颈就出现在状态与资源的更新,大量本该简化的Draw调用。虽然DX10后对draw进行了一些优化,但是还不足以让你可以忽略draw的调用方式与次数。我们应该在应用程序的调试版本中恰当使用debug runtime,根据debugRT提供的性能警告来优化程序。
为什么说draw调用的方式很影响性能呢?因为每当你调用一次draw,都会牵一发而动全身,影响到其他状态的更新。一般draw都会引起如下状态的变动:
1.const buffer的更新。
2.资源的变化(顶点缓冲,索引缓冲,纹理等等)。
3.InputLayout的变化。
Constant Buffer
常量缓冲是保存shader中常量的地方。可以用Map()/Unmap()或者Undatesubresource()来更新其中的数据。管线中的每个shader步骤,有的资料说共有16个可用cb,但是我参考MSDN发现SetVertexShaderConstant的startSlot最多只能设置D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT 个,而这个值在我的dx sdk中为14,也就是只能设置13个cb而已。在DX9中你可以通过SetXXShaderConstantX方法单独更新数据,但是DX10后每次更新都是整个cb。如果这个cb非常大,而其中只有很小的部分需要每次call都更新,那么对时间的消耗就很客观。所以比较好的解决方法就是设置多个较小的cb,每次更新就不必更新那些多余用不到的内存。
State
DX10后已经不能像DX9那样单独更新设备状态,因为DX10把所有状态封装到了一个state对象中。该对象是不可改的,所以每次你即使就是要改变state中的一项,你都要从新生成一个新的对象。所以有个方法就是你提前把所有可能用到的state对象创建好,用的时候直接提供,如果不行呢?那咱再想别的方法吧- -!
Shader Linkage
DX9是基于语义(semantic)的。DX10后是基于地址偏移的。这就导致一个限制,数据在shader中的传输不能乱序,必须按照顺序来,但是中间可以却某些变量。同时CreateInputLayout会导致一个验证“动作”的发生,所以不推荐你实时动态生成InputLayout。
Resource Update