Я сейчас программирую симуляцию и хочу перенести свое приложение с использования 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);
}
Между функциями «Начало» и «Конец» я рисую свои эллипсы стандартным способом 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);
Заранее спасибо.
Некоторое время назад я отказался от переноса кода рендеринга из GDI в Direct2D из-за низкой производительности. Как я понял из Google, производительность Direct2D зависит от оптимизации драйверов и оборудования, и вы не должны ожидать одинаковую скорость на другом оборудовании. GDI довольно старый и работает одинаково почти везде.
Должен сказать, что я пытался использовать его для рисования простых геометрических примитивов, в то время как Direct2D кажется гораздо более надежной библиотекой и, возможно, может быть повышение производительности в сложных сценариях, но это не мой случай.
Если вам нужна производительность GDI с лучшим качеством — попробуйте использовать OpenGL или Direct3D напрямую.
Это связанный вопрос:
TDirect2DCanvas работает медленно или я что-то не так делаю?
Распространенная ошибка первых попыток Direct2D заключается в том, что разработчики неправильно кэшируют ресурсы D2D, а создают и уничтожают ресурсы слишком часто. Если все ваши эллипсы имеют одинаковый размер, вы должны создать и кэшировать этот объект эллипса один раз. Если у вас есть 30 различных размеров / форм, создайте версии эллипса для всех 30 размеров / форм только один раз. Это значительно ускоряет Direct2D. То же самое касается прямоугольников и всех других примитивов. Масштабирование кэшированного объекта по сравнению с повторным созданием / уничтожением также является решением для некоторых сценариев, если существует слишком много вариаций для примитива, хотя использование ресурса с его собственным размером является идеальным, и на картах памяти достаточно места для хранения ваших ресурсов.
Эллипсы Gdi выглядят абсолютно ужасно, а использование Direct3D напрямую довольно сложно, особенно для эллипсов, больших полигонов и примитивов более высокого уровня. При правильном использовании Direct2D вы сможете получить хорошую скорость и высокое качество рендеринга.