Direct2d-Off-Screen-Rendering und Hardwarebeschleunigung

7

Ich versuche, mit direct2d Bilder mit WindowsAPICodePack außerhalb des Bildschirms zu rendern . Dies ist mit WicBitmapRenderTarget leicht zu erreichen, aber leider nicht hardwarebeschleunigt.

Also versuche ich diese Route:

  1. Erstellen Sie ein direct3d-Gerät
  2. Erstellen Sie die Textur2d
  3. Verwenden Sie die Texturoberfläche , um ein Renderziel mit CreateDxgiSurfaceRenderTarget zu erstellen
  4. Zeichne einige Formen

Während dies das Image rendert, scheint es, dass die GPU überhaupt nicht verwendet wird, während die CPU stark ausgelastet ist.

Mache ich etwas falsch? Gibt es eine Möglichkeit zu überprüfen, ob Hardware- oder Software-Rendering verwendet wird?

Codebeispiel:

var device = D3DDevice1.CreateDevice1(null,
                DriverType.Hardware,
                null,
                CreateDeviceOptions.SupportBgra,
                FeatureLevel.Ten
                );

var txd = new Texture2DDescription();
txd.Width = 256;
txd.Height = 256;
txd.MipLevels = 1;
txd.ArraySize = 1;
txd.Format = Format.B8G8R8A8UNorm; //DXGI_FORMAT_R32G32B32A32_FLOAT;
txd.SampleDescription = new SampleDescription(1,0);
txd.Usage = Usage.Default;
txd.BindingOptions = BindingOptions.RenderTarget | BindingOptions.ShaderResource;
txd.MiscellaneousResourceOptions = MiscellaneousResourceOptions.None;
txd.CpuAccessOptions = CpuAccessOptions.None;

var tx = device.CreateTexture2D(txd);

var srfc = tx.GraphicsSurface;

var d2dFactory = D2DFactory.CreateFactory();

var renderTargetProperties = new RenderTargetProperties
{
    PixelFormat = new PixelFormat(Format.Unknown, AlphaMode.Premultiplied),
    DpiX = 96,
    DpiY = 96,
    RenderTargetType = RenderTargetType.Default,
};

using(var renderTarget = d2dFactory.CreateGraphicsSurfaceRenderTarget(srfc, renderTargetProperties))
{
    renderTarget.BeginDraw();
    var clearColor = new ColorF(1f,1f,1f,1f);
    renderTarget.Clear(clearColor);
    using (var strokeBrush = renderTarget.CreateSolidColorBrush(new ColorF(0.2f,0.2f,0.2f,1f)))
    {
        for (var i = 0; i < 100000; i++)
        {
            renderTarget.DrawEllipse(new Ellipse(new Point2F(i, i), 10, 10), strokeBrush, 2);
        }
    }

    var hr = renderTarget.EndDraw();
}
Goran
quelle

Antworten:

5

Direct2D verwendet die GPU, es sei denn, Sie haben angegeben, sie nicht zu verwenden. Leider ist Direct2D tatsächlich nicht so effizient, wie wir es erwarten würden. Im gamedev-Forum gab es eine ähnliche Frage: " Schnellster Weg, um verbundene Linien zu zeichnen? " Ich habe den Test für Ihren Testfall erneut durchgeführt und die Ergebnisse sind wieder etwas beängstigend ...

Wenn Sie versuchen, 10000 Ellipsen auf dem Bildschirm zu zeichnen (Größe 10,10), empfängt die GPU effektiv:

  • 1.500.000 Scheitelpunkte => 500.000 zu rendernde Dreiecke, wenn Sie den Anti-Aliasing-Modus für das Renderziel deaktivieren
  • 4.411.734 Eckpunkte => 1.470.578 zu rendernde Dreiecke mit aktiviertem Antialias-Modus (in Ihrem Fall standardmäßig)

Da die Geometrie nicht im Voraus bekannt ist, ist der Teil des Direct2D-Codes, der auf der CPU ausgeführt werden muss, beim Aufrufen von DrawEllipse zwischen renderTarget.BeginDraw und EndDraw sehr intensiv, da alle diese Scheitelpunkte generiert werden müssen (um die Dreiecke zu triangulieren) ganze Oberfläche und erzeugen Sie winzige Dreiecke, um die äußere Linie der Ellipse abzudecken) und senden Sie alle Befehle an die GPU (mehrere hundert Direct3D10-Befehle). Jedes Dreieck bedeckt tatsächlich fast einen Pixelbereich.

Sie können die CPU-Auslastung senken, indem Sie den AntiAliased-Modus deaktivieren. Dann müssten Sie jedoch AntiAliased-Post-Effects-Shader verwenden, um das Aliasing zu verringern.

Um dies selbst zu überprüfen, können Sie Ihre Anwendung mit dem PIX-Debugger ausführen, der im DirectX SDK verfügbar ist.

Nebenbei bemerkt, Sie sollten WindowsAPICodePack nicht verwenden, da es sich um eine API handelt, die nicht wirklich effizient ist und nicht aktiv gewartet wird. Ich würde Ihnen empfehlen , SharpDX zu verwenden , das alle Direct2D / DirectWrite-Funktionen unterstützt (einschließlich Rückrufen, z. B. für Tessellation, die von keiner anderen verwalteten API unterstützt werden).

xoofx
quelle
Danke dass du dir die Zeit nimmst. Und danke für den SharpDX-Vorschlag. Werde das Projekt auf meinem Anwendungsfall testen ...
Goran
Ihre Antwort deckt es im Grunde ab, aber es gibt eine dritte Option für AA. Sie können D2D AntiAliasing deaktivieren, aber auf ein MSAA D3D-Ziel rendern und dann ResolveSubresource verwenden. Ich habe festgestellt, dass dies zu einer ähnlichen Qualität wie die Analysemethode von D2D führt, jedoch mit einer viel besseren Leistung.
Lucas
@ Lucas, in der Tat für MSAA, da es weniger Setup erfordert als die Verwendung von Anti-Aliasing-Techniken nach den Effekten wie FXAA, SMAA ... usw.
xoofx
1

Es wird zwar Hardwarebeschleunigung verwendet, die GPU wird jedoch viel weniger verwendet, da keine Zeichnung in den sichtbaren Bereich erfolgt. Die GPU-Nutzung hängt von der Kartenleistung ab. Wenn Sie dies also im High-End-Bereich versuchen, wird die GPU nur sehr wenig genutzt. Wenn Sie dies am unteren Ende versuchen (mit genügend CPU-Leistung), steigt die Nutzung auf magische Weise.

Die GPU-Nutzung zeigt Ihnen also an, ob acc aktiviert ist. Wenn RenderTargetType die Standardeinstellung ist, wird die Beschleunigung verwendet, sofern dies unterstützt wird. Wenn Sie Hardware einstellen, wird diese verwendet oder es tritt ein Fehler auf.

Wenn Sie Direct3D nicht verwenden, sollten Sie BitmapRenderTarget und d2dbitmap als Off-Screen-Puffer verwenden. Es ist schneller.

Savier
quelle