So, the beta is out!
XNA 4.0进行了大幅更新,大部分改动都不错,不过一直有2点让我非常不爽:1. render target必须和某个depth buffer绑定到一起;2. 没有了SetxxShader和SetShaderConstant等底层函数。前者对deffered shading非常不友好,后者让我写的整个材质系统都不能用了。相比之下,后者更让我担心,因为CTP中的Effect和EffectPass仅仅是DX Effect系统之上的一个简单wrapper众所周知,DirectX中Effect的性能一直是被人诟病的地方。好在Shawn告诉我:
“The Windows EffectPass.Apply implementation in the CTP is not complete, and many optimizations not yet implemented. The CTP implementation is functionally correct, but not from a performance standpoint, so you should not worry too much about Windows performance in the CTP.”
似乎Beta版已经解决了这个问题,4.0中的EffectPass不再是DX Effect上的一个简单wrapper,xna team做了很大的努力减少状态改变,以至于PIX分析xna 4.0的程序时有可能出错,Shawn在blog中说:
"The problem occurs because PIX does not support some crazy tricks that GS4 uses to optimize state management" 。
下面是同一段代码在CTP和beta版下的对比:
..... set parameter for first object
effectPass.Apply();
graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0 , 0 ,vertices.Count, 0 , primitiveCount);
// only change world matrix and draw the same object again
effect.World = Matrix.CreateTranslation( 1 , 0 , 0 );
effectPass.Apply();
graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0 , 0 ,vertices.Count, 0 , primitiveCount);
// Pix data for ctp:
ID3DXEffect::BeginPass( 0 )
ID3DXEffect::EndPass()
ID3DXEffect::End()
IDirect3DDevice9::BeginScene()
IDirect3DDevice9::DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0 , 0 , 24 , 0 , 12 ) // draw the 1 primitive
ID3DXEffect::SetMatrix( 0xFF6B4D6B , 0x0039E6F0 )
ID3DXEffect::SetMatrix( 0xFF6B4E13 , 0x0039E684 )
ID3DXEffect::SetMatrix( 0xFF6B4DBF , 0x0039E684 )
ID3DXEffect::Begin( 0x0039E7EC , 0x00000001 )
ID3DXEffect::BeginPass( 0 )
IDirect3DDevice9::SetVertexShader( 0x06487820 ) // redundance!!!!!!
IDirect3DDevice9::SetVertexShaderConstantF( 0 , 0x015851C8 , 1 ) // redundance!!!!!!!!
IDirect3DDevice9::SetVertexShaderConstantF( 14 , 0x015852A8 , 1 ) // redundance !!!!!!
IDirect3DDevice9::SetVertexShaderConstantF( 15 , 0x015852B8 , 4 )
IDirect3DDevice9::SetVertexShaderConstantF( 19 , 0x015852F8 , 3 )
IDirect3DDevice9::SetVertexShaderConstantF( 23 , 0x01585338 , 3 )
IDirect3DDevice9::SetPixelShader( 0x06486AE8 ) 3914655838 // redundance!!!!!
IDirect3DDevice9::SetPixelShaderConstantF( 0 , 0x01586D40 , 15 ) // redundance!!!!!!
ID3DXEffect::EndPass()
ID3DXEffect::End()
IDirect3DDevice9::DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0 , 0 , 24 , 0 , 12 ) // draw the 2 primitive
// Pix data for beta with d3dx function call
ID3DXEffect::BeginPass( 0 )
IDirect3DDevice9::BeginScene()
IDirect3DDevice9::DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0 , 0 , 24 , 0 , 12 )
ID3DXEffect::SetMatrix( 0xFF84502B , 0x0023E444 )
ID3DXEffect::SetMatrix( 0xFF8450D3 , 0x0023E3D8 )
ID3DXEffect::SetMatrix( 0xFF84507F , 0x0023E3D8 )
ID3DXEffect::CommitChanges()
IDirect3DDevice9::SetVertexShaderConstantF( 15 , 0x00FB5668 , 4 )
IDirect3DDevice9::SetVertexShaderConstantF( 19 , 0x00FB56A8 , 3 )
IDirect3DDevice9::SetVertexShaderConstantF( 23 , 0x00FB56E8 , 3 )
IDirect3DDevice9::DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0 , 0 , 24 , 0 , 12 )
// Pix data for beta without d3dx function:
IDirect3DDevice9::BeginScene()
IDirect3DDevice9::DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0 , 0 , 24 , 0 , 12 )
IDirect3DDevice9::SetVertexShaderConstantF( 15 , 0x007D5660 , 4 )
IDirect3DDevice9::SetVertexShaderConstantF( 19 , 0x007D56A0 , 3 )
IDirect3DDevice9::SetVertexShaderConstantF( 23 , 0x007D56E0 , 3 )
IDirect3DDevice9::DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0 , 0 , 24 , 0 , 12 )
可以看到beta版中,完全过滤了冗余的状态设置,测试代码中的effect.World会更新world marix,worldViewProjMatrix以及WorldInverseTranspose,因此渲染第二个对象前出现3个参数更新是正确的。测试程序里只渲染了2个图形,因此,BeginScene在第一次DP之前出现也是正确的。