GDI与Direct2D

roo*_*han 13 c++ winapi direct2d

我正在编程模拟,我想将我的应用程序从使用GDI移植到使用Direct2D.但我的Direct2D代码比我的GDI代码要慢得多.

我在屏幕上渲染了很多椭圆.在我的GDI应用程序中,我绘制到内存设备上下文,然后使用BitBlt在Windows设备上下文中绘制.使用Direct2D,我绘制到ID2D1HwndRenderTarget.

我的问题是,当使用GDI时,我可以轻松绘制400多个椭圆,并且仍然有400 FPS.当我使用Direct2D执行相同数量的省略号时,我的FPS下降到30FPS.

我已经关闭了antialiasing,但它并没有真正帮助.有趣的是,与GDI相比,在Direct2D中绘制几个省略号更快.我可以做些什么来提高Direct2D的性能,还是应该使用GDI保留我的应用程序?

这是我使用GDI的绘图代码:

VOID Begin() {
    SelectObject(this->MemDeviceContext, this->MemoryBitmap);
    this->BackgroundBrush = CreateSolidBrush(this->BackgroundColor);
    HBRUSH OldBrush = (HBRUSH)SelectObject(this->MemDeviceContext, this->BackgroundBrush);
    Rectangle(this->MemDeviceContext, -1, -1, 801, 601);
    SelectObject(this->MemDeviceContext, OldBrush);
    DeleteObject(this->BackgroundBrush);
    SetViewportOrgEx(this->MemDeviceContext, 400, 300, &this->OldOrigin);
}
VOID End() {
    SetViewportOrgEx(this->MemDeviceContext, this->OldOrigin.x, this->OldOrigin.y, 0);
    BitBlt(this->DeviceContext, 0, 0, 800, 600, this->MemDeviceContext, 0, 0, SRCCOPY);
}
Run Code Online (Sandbox Code Playgroud)

在我的Begin和End函数之间,我使用标准的GDI方式绘制省略号.

以下是使用Direct2D的开始和结束函数:

VOID BeginDrawing() {
    this->RenderTarget->BeginDraw();
    RenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::CornflowerBlue));
    RenderTarget->SetTransform(this->ScalingMatrix * this->TranslateMatrix);
}
VOID EndDrawing() {
    this->RenderTarget->EndDraw();
}
Run Code Online (Sandbox Code Playgroud)

以下是我如何设置Direct2D接口.这一切都包括在课堂上; 这就是我无法发布完整代码的原因:

    if(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &Direct2DFactory) != S_OK)
        throw std::runtime_error("RENDERWINDOW::InitializeDirect2D: Failed to create a factory interface.");
    RECT WindowRect;
    memset(&WindowRect, 0, sizeof(RECT));
    GetClientRect(this->WndHandle, &WindowRect);
    D2D1_SIZE_U WindowSize = D2D1::SizeU(WindowRect.right, WindowRect.bottom);
    Direct2DFactory->CreateHwndRenderTarget(D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_HARDWARE), 
    D2D1::HwndRenderTargetProperties(this->WndHandle, WindowSize, D2D1_PRESENT_OPTIONS_IMMEDIATELY), &RenderTarget);
Run Code Online (Sandbox Code Playgroud)

先感谢您.

Rob*_*ert 32

首次尝试Direct2D时常见的错误是开发人员没有正确缓存D2D资源,而是经常创建和销毁资源.如果所有省略号的大小相似,则应创建并缓存此椭圆对象一次.如果您有30种不同的尺寸/形状,则只为所有30种尺寸/形状创建椭圆版本一次.这显着加速了Direct2D.矩形和所有其他基元也是如此.如果基元存在太多变体,则缩放缓存对象与重复创建/销毁也是一种解决方案,尽管使用其原始大小的资源是理想的,并且存储卡具有相当多的内存来存储资源.

Gdi椭圆看起来非常糟糕,直接使用Direct3D相当复杂,特别是对于椭圆,大多边形和更高级别的基元.正确使用Direct2D后,您应该能够获得良好的速度和高质量的渲染.

  • 这是实际的答案. (8认同)
  • 我可以补充一下,Direct3d 不是答案,因为在缓存/预创建几何图形方面,您必须执行与在 Direct2d 中执行的操作完全相同的操作,才能从中获得最佳性能。Direct2d 建立在 Direct3d 的基础上,在很大程度上消除了用它制作 2D 图形的痛苦,特别是画笔、AA、线条等。 (2认同)
  • D2D 和 D3D 有很大不同。它们可以共享内存、创建复合渲染,但 D2D 场景与 D3D 场景的准备和渲染是不同的。虽然复合起来并不难。对场景的边框、文本、各种稀疏部分使用 D2D,然后对场景的大数据部分添加 D3D。用于 2D 的 D3D 是比完整 3D 更简单的渲染形式,但所有内容仍然是线或三角形拓扑,因此计划使用三角学来创建 D3D 世界中带有顶点的所有内容。D2D 使您不必只使用顶点。 (2认同)

Eug*_*ene 5

前段时间,由于性能低下,我拒绝将渲染代码从 GDI 迁移到 Direct2D。正如我从谷歌了解到的,Direct2D 性能取决于驱动程序和硬件优化,您不应该期望不同硬件上的速度相同。GDI 已经很老了,几乎在任何地方都能正常工作。

必须说我已经尝试使用它来绘制简单的几何图元,而 Direct2D 似乎是更健壮的库,并且可能在复杂场景中可以提高性能,但这不是我的情况。

如果您需要更高质量的 GDI 性能 - 尝试直接使用 OpenGL 或 Direct3D。

这是一个相关的问题: TDirect2DCanvas 慢还是我做错了什么?

  • Direct2D 依赖于 DirectX 10/11 驱动程序的存在。在它不存在的情况下,Direct2D 将退回到软件渲染,在这种情况下,它的性能最差与 gdi 相当。当硬件支持 DirectX10/11 时,Direct2D 的性能远超 gdi。GDI+ 是一个很好的尝试,但是 GDI+ 的性能比 gdi 差。老实说,最好的答案是让 OP 使用他喜欢的东西,然后在他得到一个可以工作的应用程序之后,如果它没有达到他想要的性能,优化! (5认同)
  • 从 GDI 移植到 GDI+ 应该很简单。GDI+ 支持抗锯齿输出,因此质量与 Direct2D 一样好,而且 GDI+ 的性能仍然比 Direct2D 好得多。 (2认同)