Optimize Shader Constant Update in XNA 4.0

时间:2021-05-11 05:27:07

 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的做法,终于坚定了信心,明天开始改代码-,-