16

現在、シミュレーションをプログラミングしており、GDI を使用するアプリケーションから Direct2D を使用するアプリケーションに移植したいと考えています。しかし、Direct2D コードは GDI コードよりもはるかに遅いです。

画面上にたくさんの楕円をレンダリングします。私の GDI アプリケーションでは、メモリ デバイス コンテキストに描画し、BitBlt を使用して Windows デバイス コンテキストに描画します。Direct2D では、ID2D1HwndRenderTarget に描画します。

私の問題は、GDI を使用すると、400 以上の楕円を簡単に描画でき、それでも 400 FPS を維持できることです。Direct2D で同じ数の楕円を実行すると、FPS が 30FPS まで低下します。

すでにアンチエイリアスをオフにしていますが、あまり役に立ちません。興味深いことに、いくつかの楕円を描くだけでも、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);
}

Begin 関数と End 関数の間に、標準的な GDI の方法で楕円を描画します。

Direct2D を使用した begin 関数と end 関数は次のとおりです。

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

前もって感謝します。

4

3 に答える 3

40

Direct2D の最初の試行でよくある間違いは、開発者が D2D リソースを適切にキャッシュせず、代わりにリソースを頻繁に作成および破棄することです。すべての楕円が同様のサイズである場合は、この楕円オブジェクトを一度作成してキャッシュする必要があります。30 個の異なるサイズ/形状がある場合は、30 個すべてのサイズ/形状の楕円バージョンを 1 回だけ作成します。これにより、Direct2D が大幅に高速化されます。Rectangles と他のすべてのプリミティブについても同じことが言えます。プリミティブのバリエーションが多すぎる場合は、キャッシュされたオブジェクトをスケーリングするのではなく、作成/破棄を繰り返すこともいくつかのシナリオの解決策ですが、リソースをネイティブ サイズで使用することが理想的であり、メモリ カードにはリソースを格納するためのかなりのメモリがあります。

Gdi の楕円は非常に見栄えが悪く、Direct3D を直接使用することは、特に楕円、大きなポリゴン、および高レベルのプリミティブの場合、かなり複雑です。Direct2D を適切に使用すると、優れた速度と高品質のレンダリングを実現できるはずです。

于 2013-09-22T22:01:19.050 に答える
5

少し前に、レンダリング コードを GDI から Direct2D に移行することを、パフォーマンスが低いという理由で拒否しました。私がグーグルから理解しているように、Direct2D のパフォーマンスはドライバーとハードウェアの最適化に依存しており、異なるハードウェアで同じ速度を期待するべきではありません。GDI はかなり古く、ほぼどこでも同じように機能します。

Direct2D ははるかに堅牢なライブラリであり、複雑なシナリオではパフォーマンスが向上する可能性がありますが、これは私の場合ではありません。

より良い品質の GDI パフォーマンスが必要な場合は、OpenGL または Direct3D を直接使用してみてください。

これは関連する質問です: TDirect2DCanvas は遅いですか、それとも何か間違っていますか?

于 2012-11-08T05:04:26.203 に答える