Search code examples
c++winapidirect2d

GDI versus Direct2D


I'm programming a simulation at the moment, and I want to port my application from using GDI to using Direct2D. But my Direct2D code is much slower than my GDI code.

I render a lot of ellipses on the screen. In my GDI application I draw to a memory device context and then use BitBlt to draw on the windows device context. With Direct2D, I draw onto a ID2D1HwndRenderTarget.

My Problem is, when using GDI, I can draw easily 400+ ellipses and still have 400 FPS. When I do the same number of ellipses with Direct2D, my FPS drops down to 30FPS.

I already switched antialiasing off but it doesn't really help. The interesting thing is that drawing just a few ellipses is faster in Direct2D compared to GDI. Is there anything I can do to improve the performance in Direct2D, or should I keep my application using GDI?

Here is my drawing code using 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);
}

Between my Begin and End function, I draw my ellipses the standard GDI way.

Here are my begin and end functions using Direct2D:

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

And here is how I set up my Direct2D interfaces. It's all wrapped in class; that's why I cant post the full code:

    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);

Thank you in advance.


Solution

  • Some time ago I’ve refused migrating rendering code from GDI to Direct2D due to low performance. As I understand from google, Direct2D performance depends on driver and hardware optimizations and you shouldn’t expect the same speed on different hardware. GDI is pretty old and works equally almost everywhere.

    Must say I’ve tried to use it for drawing simple geometry primitives whereas Direct2D seems to be much more robust library and maybe there could be performance boost on complex scenarios, but this is not my case.

    If you need GDI performance with better quality – try to use OpenGL or Direct3D directly.

    This is a related question: Is TDirect2DCanvas slow or am I doing something wrong?