2月22日更新《DirectX11的Shader Reflect的几个问题》

又看了看U3的实现方式,写了些新的东西:原文见:
http://blog.csdn.net/noslopforever/article/details/7269353


节选:


2.2.1-----2012-2月22日更新----关于U3

又看了看U3 CBuffer这块儿的组织,不是怪异,而是牛逼。

U3因为它整个渲染引擎是具有一整套完整的体系的,而且借助于其优秀的Vertex Factory / Material Template设计,所以可以做到一开始就把所有的Constant全部合理安排的地步,因此它把自己所可能用到的所有CB按照频率和其它因素设置成了8个Buffer。

例如,其Vertex Factory相关的Buffer,在整个Static Mesh的各个SubMesh渲染完之前,是不会Update的,因为没有Update的必要,里面记录的World Matrix信息在这中间是不会改动的。

这样合理的划分即便是相比于使用Effect Pool,也要合理很多,而很多人使用Effect连Effect Pool都不用,性能上的浪费可想而知!因为Effect的实现,是每个Effect自己为自己下属的所有Shader保存一个Cbuffer Cache的,每切换一次Effect,哪怕Shader本身没有变化,CBuffer都会强制重新提交。而且更重要的是,Shader间的CBuffer不共享,明明两个Shader的某个CBuffer的信息完全一样,但只是因为Shader不一样,这个Shader的World Matrix变化还需要在另一个Shader里面设置一次,使得CBuffer重新提交的数量级迅速增加。而U3的组织流程就不存在这个问题。

当然了,整个游戏每次只需要渲染不到100个批次,你用Effect和自己管理Shader代价当然差不了多少了。

但是10000个呢?材质爆炸后呢?单不同Shader的这些Cache Buffer的浪费就是一个恐怖的数量。须知Unreal3就算在材质良好设计大量使用Material Instance的情况下,Shader Pool仍能保持在K这个数量级,还是没开DX11的,K个Shader的Cached Buffer,如果每个Shader独立存储的话,再加上需要临时记录在内存里的Shadow Buffer,是什么概念呢?可想而知。

但是,为什么U3可以这么做呢?是因为它不是一个通用化图形引擎,而是一个体系化的游戏引擎。

通用化图形引擎你不知道别人会怎么使用你的引擎,有些人做《Magicka》那样的小品级游戏(没有任何别的意思,我很喜欢这种小品级游戏),你迫使他花精力去管理各种Buffer组织什么的,人家才不跟你玩那个呢,XNA比你这套方便多了。

但还有些人,整个场景里1000个物体,1000种不同的材质,每个材质都一个独立Shader,这种游戏你如果只支持Effect式的方案就麻烦了,浪费+切换,在这方面可能就会落后一些。

所以,根据实际情况来选择吧。


2.2.2——2012-2-22——关于KlayGE的CBuffer(?)

“印象里,Klay并没有把CB按照RB里的Binding Point重排位置,而是按照CBuffers的获取时传入的Index(就是foreach CBuffers那会儿)直接建立了CB表,这两者是否真正一致?”

手头暂时没有Klay,之前看过,也不敢确认自己到底是不是记得准确。Klay是个优秀的引擎,事实上去年自己用过一段时间,很好用,写的也很不错。这里本文并无意于去讨论Klay,本文还是主要想讨论CB的使用和组织问题,如果这里小生记错了,还望龚大海涵。

这个问题的答案是—— 不一致 如果在使用CBuffer时,强制通过register(b13)把CBuffer设到靠后的位置,就会很快发现这种不一致。

所以,组织CBuffer时,千万记得按照Resource Binding里的Binding Point信息重排CBuffer的位置,否则在后面Set Constant Buffer时,传入的Index就有可能是错的

例如我建立了1个CBuffer,在register b13,但是按照Desc.ConstantBuffers获取出来的数量是1个,所以如果按照ConstantBuffers来阻止的话,这个CB的索引是0,而不是13,提交时如果也按照这个索引提交,就会把本身应提交到13的CB提交给0。




2.3.1——2012-2-22——再论U3的组织

上面说到的问题,感觉U3的那个思路也是很不错的,但是就像之前所说的,那是一种体系化游戏引擎的思路,对于做通用化图形引擎来说并没有太多的参考价值。因为实际的使用者很可能并不能像U3那样去把整个应用程序的CBuffer安排出来,而且这样做对于使用者本身的要求就太高了,会把很多创意高手、图形新手给拒之门外。

另外就是也可以考虑一下Effect Pool的那个思路,把一些可能会共享的参数通过一个Pool,来使得若干个从此Pool产生的Shader可以共享。但是Effect Pool本身事实上是通过对Effect脚本语法分析得出来的,如果要做这个,而不想在D3D的基础上引出太多概念,要怎么做确实还是一个新的问题。

引擎要做成什么样,只有做引擎的人最了解,没有一成不变的方案,只有最适合自己的方案。No Silver Bullets,任何时候都别忘记这一点,既然没有银弹,与其花时间去追寻“一揽子解决方案”,不妨更多时候考虑考虑“他想要什么”。


2.4 关于Samplers、Textures的组织

这玩意基本上比前面的CBuffer要简单,因为它不存在着一个CBuffer里好几个Sampler,Texture每个要去算Offset的问题。
所以只需要围绕着各自Resource Binding的BindingPoint、BindingCount建表即可,也是需要注意Binding Point的问题,Texture和Sampler也是可能会通过register给强制设到后面的。
此外,Sampler、Textures还需要注意的一点在于他们是可以“Array化”的。
是的:
Texture2D GMRTs[4];
可以这样。
有什么不同吗?
两点:
第一,他们的Array信息记录在BindingCount里,上面的情况,BindingCount就不再是正常情况下的1了,而是4。这个是废话,因为前面已经强调过这个问题了。
最需注意的在于第二点,你通过Name获得到的这个变量的变量名不是GMRTs,而是GMRTs[4]!所以如果按照经验,直接把这个Name放到变量表里,后面您可就找不到这个变量咯。
解决方案不麻烦:放到变量表前,先看看有木有“[x]”,有的话干掉,然后再放到变量表即可。
还需注意的是,Texture和Sampler跟CB一样,也是可以在不同的Shader间通用的喔~~所以,优化CBuffer的思路也可以跟这些放到一起来做的~


你可能感兴趣的:(游戏,buffer,引擎,binding,shader,textures)