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之前出现也是正确的。