16

这是对这个问题的跟进。我目前正在编写一个简单的游戏,并且正在寻找在 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();
4

3 回答 3

7

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

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

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

就您而言,这无关紧要-无论如何,您都在谈论将数据从CPU空间移动到GPU空间。使用 DirectX(或 OpenGL)的主要速度差异发生在您将所有(或大部分)计算保留在 GPU 上,并完全避免使用 CPU(或主内存)时。它们没有(现在 AGP 已成为历史)在内存->显示带宽方面提供任何实质性改进。

于 2010-11-08T22:25:49.910 回答
3

Jerry Coffin 提出了一些很好的观点。要记住的是 DI 在 SetDIBitsToDevice 中代表什么。它代表设备独立。这意味着你总是受司机的摆布。一些驱动程序过去完全是垃圾,它极大地影响了性能。DirectDraw 也遇到了类似的问题……但您也可以访问硬件 blitter,因此它通常更有用。由于 DirectDraw 的游戏关联性,IHV 也倾向于投入更多时间为 DirectDraw 编写适当的驱动程序。当硬件完全有能力做得更好时,谁想成为性能堆的底部?

如今,许多显卡可以直接接受位数据,因此不会发生转换。如果确实需要搅拌,这在当今时代也非常快。

相比之下,您的 Direct3D 性能如此糟糕的原因是 Direct3D 本质上是完全在 GPU 内部使用的,它使用奇怪和复杂的格式来提高缓存性能等等。

再加上您没有通过创建纹理/表面、锁定、复制、解锁然后在后台缓冲区上绘制(通过各种方法)来测试类似(使用 DDraw 和 D3D)的事实。为了获得最佳性能,您最好使用 DISCARD 锁直接锁定后台缓冲区,然后在解锁之前直接将 memcpy'ing 到返回的缓冲区中。这将使您的性能更接近 SetDIBitsToDevice。但是,出于上述原因,我仍然希望 D3D 比 DDraw 慢。

于 2010-11-09T11:38:29.250 回答
1

你会听到人们对 GDI 大打出手的原因是它曾经只是旧的 Windows API 调用。它的较新版本(我上次查看 em 时称为 GDI+)实际上只是放置在 DirectX 调用之上的 API。因此,有时使用 GDI 可能看起来相当简单,但在事物之间添加一层总是会减慢速度。正如 Jerry Coffin 的回复中提到的,您的示例是关于移动数据的,这就是缓慢的时间。我有点惊讶 DirectX 的速度要慢得多,但我无法通过挖掘 DirectX 文档来获得更多帮助(这在相当长一段时间内真的非常棒......可能想看看 www.codesampler.com . 我总是从他那里找到很好的起点,实际上,虽然我可能会因为这样说而发疯,

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

任何人,希望这有帮助!

PS:需要注意的是,DirectX 并不总是最快的。对于键盘输入(除非这在 10 或 11 中发生了变化),几乎总是建议使用 windows 事件。因为 DirectInput 实际上只是该系统的包装器!.. XInput 然而 - 太棒了 - !

于 2010-11-09T06:59:04.013 回答