Xna框架问题

时间:2011-08-22 08:04:59

标签: xna directx

我正在查看Xna Framework Game类的源代码,特别是它如何进行Draw调用,我可以看到对GraphicsDevice.Present()的调用 GraphicsDeviceManager.EndDraw(),但我找不到对GraphicsDevice.BeginScene()的调用或 GraphicsDevice.EndScene(),甚至不在GraphicsDevice类本身。任何人都知道他们如何处理这种情况。

1 个答案:

答案 0 :(得分:7)

您没有找到对GraphicsDevice.Begin/EndScene()的引用的原因是因为这些方法不存在。 GraphicsDevice类是一个托管类,用于封装XNA框架用户所需的图形功能;它不是本地IDirect3DDevice9接口的一对一映射。

我假设通过查看源代码,你的意思是使用像Reflector这样的东西,我也假设你把代码看作C#代码。要记住的一件重要事情是XNA框架的大部分是用C ++ / CLI编写的,因此当反映到C#时,结果可能有些不可预测。

对于调用原生IDirect3DDevice9::BeginScene()IDirect3DDevice9::EndScene()的具体情况,您需要稍微挖掘一下。

以下所有内容均假设为XNA 4.0。 3.1应该仍然相似。在Reflector中,您会注意到GraphicsDevice类有私有bool _insideScene。如果您对此进行分析,您会看到它设置在各个位置,例如GraphicsDevice.DrawPrimitives()来电。此方法的C#反射应使用以下代码设置此成员:

if (!this._insideScene)
{
    **(((int*) this.pComPtr))[0xa4](this.pComPtr);
    this._insideScene = true;
}

这里的关键是**(((int*) this.pComPtr))[0xa4](this.pComPtr);。如果您要编写C ++ / CLI程序集,请在d3d9.h的实例(即BeginScene())中包含相应的DirectX标头(IDirect3DDevice9)并调用pDevice->BeginScene(),然后进行反汇编你在C#中组装,你会有一条与上面相同的线。这就是本机调用的IL映射回C#,的方式,但是不可能在C#中编写该行并编译它

代码行本质上是一个原始的虚方法调用。您可以阅读有关虚拟方法表here的更多信息,但是对于这种情况,它的基本内容如下:对象的虚拟表指针(依赖于编译器,但在这种情况下为true)是第一个元素原生物体。 pComPtr是指向本机COM IDirect3DDevice9对象的不安全指针。因此,解除引用pComPtr*pComPtr)会为您提供指向虚方法表的指针。这里的反汇编有点模棱两可,但IL很清楚。接下来发生的是0xa4被添加到虚方法表指针。要理解这一点,请记住本机数组只是指向数组第一个元素的指针。对象的虚方法表是一个函数指针数组。 0xa4是十进制的164,表示指针向前移动164个字节。由于库是一个x86库,指针长度为4个字节。这意味着我们已经转移到虚拟方法表(164 / 4 = 41)中的第41个方法。如果您查看IDirect3DDevice9(DirectX SDK的一部分)中的d3d9.h接口声明,您会看到第41个方法是BeginScene。然后取消引用此指针以提供实际的BeginScene方法,然后调用传入(通常隐藏的)this指针作为第一个(也是唯一的)参数(其中this为本机call是this.pComPtr指针。

您可以在私有不安全GraphicsDevice.Present()方法中看到类似的代码,此时偏移到0xa8或函数42,即IDirect3DDevice9::EndScene()

因此,您可以看到GraphicsDevice正确确保在完成任何绘图之前已调用BeginScene,并且在调用本机EndScene方法之前调用IDirect3DDevice9::Present() ,但它故意隐藏XNA框架用户的这一功能。