如何高效更新Direcx11的各种资源与状态

来源:互联网 发布:淘宝客服外包怎么样 编辑:程序博客网 时间:2024/05/29 13:35

在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

D3D10_USAGE_DEFAULT
D3D10_USAGE_IMMUTABLE
D3D10_USAGE_DYNAMIC
D3D10_USAGE_STAGING
这四个flag直接影响到数据的存放位置,进而影响数据被GPU或者CPU的读写效率。DEFAULT用于GPU快速读写,并且只能用updatesubresource()来更新。IMMUTABLE用于被GPU只读,其中存放的数据不可变。DYNAMIC提供快速的CPU写和较慢的GPU读。只能用Map()来更新。STAGING提供了一种方式让你可以读取GPU写回的数据。
简要概括来说:
需要CPU经常更新的数据用DYNAMIC,需要CPU经常更新的可用DEFAULT,完全不需要CPU更新的数据用IMMUTABLE,CPU需要读的用STAGING。
综上所述,我们的cb一般是要经常被更新的,所以用DYNAMIC较为合适,进而可推断,用Map较合适,同时NVDIA也表达推荐使用DYNAMIC+Map。这个跟硬件实现其实关系也挺大。UpdateSubresource()需要系统内存和额外的拷贝操作,而Map()则不需要这些。
 
 
【1】Shanon Drone,Take it to The Next Level,Game fest2007
0 0
原创粉丝点击