Clayman's Graphics Corner

DirectX,Shader & Game Engine Programming

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

 Optimize Shader Constant Update in XNA 4.0

作者:clayman

仅供个人学习使用,请勿转载,勿用于任何商业用途。

 

      虽然xna 4.0删除了SetShaderConstant等一系列方法,让我们不能以最高效的方式更新shader参数,但通过优秀的设计,仍然有很大优化空间。我们的目标有两个:

1.减少状态改变 --- 这是任何shader constant management系统的首要目标;

2.减少EffectParameter.SetValue的调用--- reflector可以看到,这是一个非常慢的函数;

 

         如何实现呢?DirectX 10为我们指明了方向,那就是constant buffer(cb)。虽然dx 9下并没有cb,但这并不妨碍我们模拟出类似的机制,要做的不过是稍稍改变编写shader的方式而已:

float4 PerFrameConstants[n] :register(c0);
float4 MaterialConstant[m]:register(n);
float4 InstanceConstant[v] : register(n
+m);

 

 

        不再声明众多独立的uniform变量,而是把他们看做不同类型变量组中的元素,这几乎和dx 10cb的概念一模一样。为了方便编写,可以在shader中,重新组织这些变量,比如:

static float4*4 viewProj = float4*4(PerFrameConstants[0], PerFrameConstants[1], PerFrameConstants[2], PerFrameConstants[3]);
static float4*4  worldMatrix = float4*4( InstanceConstant[0], InstanceConstant[1], InstanceConstant[2], InstanceConstant[3]);

………………………………

 

 

        对应用程序来说,原来众多不同类型的参数,缩减为了非常少的几个数组。所有shader constat的改变都先缓存到数组中,然后一次性提交:

Vector4[] InstanceConstant;
InstanceConstant.SetValue(startIndex,elementCount, value);
//……………set other constant
EffectParameter.SetValue(InstanceConstant);

 

 

        虽然上面的伪代码中InstanceConstant.SetValueEffectParameter.SetValu看起来非常类似,性能却相差很多倍:InstanceConstant.SetValue只是找到特定的数组元素,并为其赋值而已;EffectParameter.SetValue就包括了一系列参数类型验证,从manage codenative code的调用,以及底层DX的函数调用等等。

         当然,性能的提升并不是免费的,改写shader以后,我们需要额外的信息知道某个参数位于哪个数据中的哪几个元素,此外,与dx10一样,cb划分的好坏,对性能有很大影响。

         最后,除性能以外,这样的方法还有一个额外的好处,就是统一了dx9/10的参数更新方式,对那些非xna,同时支持多个dx版本的传统引擎来说,也非常适合,Just Cause 2就是这么做的J

 

 

ps:老早就就打算这么干,但犹犹豫豫怕把接口设计的太复杂,今天看了Just Cause2的做法,终于坚定了信心,明天开始改代码-,-

 

 

posted on 2010-07-28 23:26  clayman  阅读(1456)  评论(4编辑  收藏  举报