Подтвердить что ты не робот

GDI против Direct2D

Я программирую симуляцию на данный момент, и я хочу перенести приложение с помощью GDI на использование Direct2D. Но мой код Direct2D намного медленнее, чем мой код GDI.

Я рисую много эллипсов на экране. В моем приложении GDI я рисую в контексте устройства памяти, а затем использую BitBlt для рисования контекста устройства Windows. С Direct2D я рисую ID2D1HwndRenderTarget.

Моя проблема в том, что при использовании GDI я могу легко рисовать 400 эллипсов и до сих пор иметь 400 FPS. Когда я делаю то же количество эллипсов с Direct2D, мой FPS падает до 30FPS.

Я уже отключил сглаживание, но это действительно не помогает. Интересно, что рисование всего нескольких эллипсов происходит быстрее в Direct2D по сравнению с GDI. Есть ли что-нибудь, что я могу сделать, чтобы улучшить производительность в 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);
}

Между моей функцией 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();
}

И вот как я настроил свои 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);

Спасибо заранее.

4b9b3361

Ответ 1

Некоторое время назад Ive отказался от переноса кода рендеринга из GDI в Direct2D из-за низкой производительности. Как я понимаю из Google, производительность Direct2D зависит от оптимизации драйверов и аппаратных средств, и вы не должны ожидать такой же скорости на разных аппаратных средствах. GDI довольно старый и работает практически везде.

Должен сказать, что Ive пыталась использовать его для рисования простых примитивов геометрии, тогда как Direct2D кажется гораздо более надежной библиотекой и, возможно, может быть повышение производительности в сложных сценариях, но это не мой случай.

Если вам нужна производительность GDI с лучшим качеством - попробуйте напрямую использовать OpenGL или Direct3D.

Это связанный вопрос: Является ли TDirect2DCanvas медленным или я делаю что-то неправильно?

Ответ 2

Общая ошибка с первыми попытками Direct2D заключается в том, что разработчики не кэшируют ресурсы D2D должным образом, а слишком часто создают и уничтожают ресурсы. Если все ваши эллипсы имеют одинаковый размер, вы должны создать и кешировать этот объект эллипса один раз. Если у вас есть 30 разных размеров/форм, создайте эллиптические версии для всех 30 размеров/фигур только один раз. Это значительно ускоряет работу Direct2D. То же самое касается Rectangles и всех других примитивов. Масштабирование кэшированного объекта по сравнению с повторным созданием/уничтожением также является решением для некоторых сценариев, если существует слишком много вариаций для примитива, хотя использование ресурса в его собственном размере идеально, а карты памяти имеют довольно небольшую память для хранения ваших ресурсов.

Эллипсы Gdi выглядят абсолютно ужасно, и использование Direct3D напрямую довольно сложно, особенно для эллипсов, больших полигонов и примитивов более высокого уровня. При правильном использовании Direct2D вы сможете получить хорошую скорость и высококачественный рендеринг.