为什么不使用GDI重复填充数组中RGB数据的窗口?

时间:2010-11-08 21:52:22

标签: winapi directx gdi directdraw

这是this question的后续行动。我正在编写一个简单的游戏,我正在寻找在Win32窗口中(重复)显示RGB数据阵列的最快方法,而不会出现闪烁或其他伪影。

在前一个问题的答案中建议采用几种不同的方法,但没有达成共识,哪种方法最快。所以,我把测试程序汇总在一起。代码只是在屏幕上反复显示帧缓冲,尽可能快。

这些是我获得的结果,对于以32位视频模式运行的32位数据 - 他们可能会让一些人感到惊讶:

- Direct3D (1):             500 fps
- Direct3D (2):             650 fps
- DirectDraw (3):          1100 fps
- DirectDraw (4):           800 fps
- GDI (SetDIBitsToDevice): 2000 fps

鉴于这些数字:

  • 为什么许多人坚持认为GDI对于此操作来说太慢了?
  • 是否有理由比SetDIBitsToDevice更喜欢DirectDraw或Direct3D?

以下是每个Direct *代码路径调用的简短摘要。如果有人知道使用DirectDraw / Direct3D的更有效方法,请发表评论。

1. CreateTexture(D3DUSAGE_DYNAMIC, D3DPOOL_DEFAULT);
       LockRect(); memcpy(); UnlockRect(); DrawPrimitive()

2. CreateTexture(0, D3DPOOL_SYSTEMMEM); CreateTexture(0, D3DPOOL_DEFAULT);
       LockRect(); memcpy(); UnlockRect(); UpdateTexture(); DrawPrimitive()

3. CreateSurface(); SetSurfaceDesc(lpSurface = &frameBuffer[0]);
       memcpy(); primarySurface->Blt();

4. CreateSurface();
       Lock(); memcpy(); Unlock(); primarySurface->Blt();

3 个答案:

答案 0 :(得分:6)

这里有几点要记住。首先,许多“常识”是基于一些不再适用的事实。

在AGP时代,当CPU直接与GPU通信时,它总是使用基本PCI协议,它以“1x”速率发生(总是并且不可避免地)。当GPU直接进入内存控制器时,仅应用AGX 2x / 4x / 8x 。换句话说,根据你看的 时,GPU从内存中加载纹理的速度是CPU的最高速度的8倍,因为CPU将相同的数据直接发送到GPU。当然,CPU也比支持的PCI总线拥有更多的内存带宽。

然而,当事情切换到PCI-E时,情况完全改变了。虽然根据路径可能存在带宽差异,但是没有一般规则,内存 - > GPU将比CPU-> GPU更快。 (大多数情况下)安全的一个概括是如果你有一个专用的显卡,那么GPU几乎总是会有更多带宽到显卡的内存,而不是主板上的主内存

在你的情况下,这并不重要 - 你所谈论的是无论如何将数据从CPU空间移动到GPU空间。使用DirectX(或OpenGL)时的主要速度差异发生在GPU上保留所有(或大部分)计算,并且完全避免使用CPU(或主存储器)。他们没有(现在AGP是历史)在内存中提供了任何实质性的改进 - >显示带宽。

答案 1 :(得分:2)

杰瑞科芬提出了一些好处。要记住的是DI在SetDIBitsToDevice中所代表的含义。它代表设备无关。这意味着你总是受到司机的摆布。一些司机曾经是完全垃圾,并且大规模地影响了性能。 DirectDraw也遇到了类似的问题......但你也可以访问硬件blitters,因此它通常更有用。由于其游戏关联,IHV还倾向于花更多的时间为DirectDraw编写适当的驱动程序。当硬件能够做得更好时,谁想成为性能堆的底部?

现在很多显卡都可以直接接受位数据,因此不会发生转换。如果它确实需要调整,那么在这个时代也很快。

相比之下,Direct3D性能如此糟糕的原因在于,Direct3D本质上意味着它完全在GPU内部使用,它使用奇数和复杂格式来提高缓存性能等等。 / p>

通过创建纹理/表面,锁定它,复制,解锁然后绘制后缓冲区(通过各种方法)来表示你没有像喜欢(使用DDraw和D3D)那样的事实。为了获得最佳性能,最好使用DISCARD锁定直接锁定后备缓冲,然后在解锁前直接记忆到返回的缓冲区。这将使您的性能更接近SetDIBitsToDevice。我仍然期望D3D比DDraw慢,原因如上所述。

答案 2 :(得分:1)

你会听到人们在GDI上遇到麻烦的原因是它曾经只是旧的Windows API调用。它的较新版本(我上次查看em时称为GDI +)实际上只是放置在DirectX调用之上的API。因此,有时使用GDI可能看起来相当简单,但在事物之间添加一层总是会减慢速度。正如Jerry Coffin的回应中所提到的,你的例子是关于移动数据的,这是一个缓慢的时间。我有点惊讶的是DirectX虽然速度要慢得多,但我不能在挖掘DirectX文档方面提供更多帮助(这已经非常棒了很长一段时间了..可能想看看www.codesampler.com我总是从他那里找到了很好的起点,实际上,虽然我可能会因此而疯狂,但我会发誓对doc中的DirectX SDK进行了改进,并根据这些人的工作做了示例!)

至于DirectDraw与Direct3D(而不是GDI调用)的讨论。我会说去Direct3D。我相信DirectDraw自8.0以后就被弃用了,9.0已经存在了很长时间。并且在一天结束时,所有DirectX都是3D,它只是在周围有用的2D api的级别上变化,但是当您实际使用3D空间时,您可能会发现在2D环境中可以做一些非常有趣的事情。 (我有一个非常整齐的随机生成的闪电武器,一次空间入侵者克隆:))

Anywho,希望这有帮助!

PS:应该注意的是,DirectX并不总是最快的。对于键盘输入(除非在10或11中已经改变),几乎总是建议使用windows事件..因为DirectInput实际上只是该系统的包装器!..但是XInput是-awesome - !!