2015-01-12 8 views
5

Ich habe ein SharpDX-Projekt, das sehr kurz vor der Fertigstellung ist. Es verwendet eine Kinect für die Interaktion. Aus diesem Grund verwendet mein Projekt WPF sowohl für die Kinect-Region als auch für das KinectUserViewer-Objekt. SharpDX hat für alles bisher gut funktioniert, aber wenn es zu einem bestimmten Teil des Programms kommt, das Direct3D stark verwendet, beginnt es zu flackern. Dies ist offensichtlich mit der Tatsache verbunden, dass D3Dimage (verwendet von dem SharpDXElement in MainWindow.xaml) "grundlegend gebrochen und für effizientes D3D-Rendering in WPF" [1] ungeeignet ist. Gibt es eine Möglichkeit, meine WPF-Elemente zu behalten und nicht mit Direct3D zu flackern?Brauchen SharpDXElement Alternative. Workaround zu sharpDX WPF flackern

+0

Können Sie einige zugehörigem Code zeigen, bitte? Es würde enorm helfen zu sehen, wo Sie sind, wenn Sie eine Frage wie diese beantworten. – rfornal

+0

Es hat mehr als 15000 Zeilen Code. Es ist schwer, relevanten Code zu finden. Es verwendet die Klasse toolkit.game für die Zeichen- und Aktualisierungsschleife. Ich benutze in erster Linie Spritebatch, aber Teile davon verwenden sowohl XNA und Direct3D, einschließlich der fraglichen Teil. Gibt es einen bestimmten Teil, von dem Sie glauben, dass er helfen würde? – Asor

+0

Angenommen, ich habe mir Ihren Link angesehen und als ich den Kontext Ihres Angebots betrachtet habe, wurde auch eine eingeschränkte Problemumgehung mit einem Windows-Formular erwähnt. Wenn ich die Problemumgehung verstanden hätte, würde das im Wesentlichen ein Windows-Formular im D3DImage-Ersatzbereich enthalten - und ich denke, dass * nur * dieser Bereich keine XAML-Elemente verwenden könnte. Würde das für dich funktionieren? Oder fehlt mir etwas an der Art der Problemumgehung? –

Antwort

5

Flackern bedeutet wahrscheinlich, dass die GPU nicht fertig ist und den Frame gerendert hat, bevor D3DImage versucht, sie in den Frontpuffer zu kopieren. Dies kann leicht in WPF auftreten, da WPF den Standardmechanismus nicht verwendet, um eine Swap-Kette zum Rendern eines Frames bereitzustellen. Stattdessen verwenden die meisten Code etwa wie folgt:

// rendering code 
Device.Flush(); // or equivalent, depending on Direct3D version used 
D3DImage.Lock(); 
D3DImage.AddDirtyRect(...); 
D3DImage.Unlock(); 

, dass zumindest das Muster von SharpDXElement.InvalidateRender gefolgt ist - ich habe nicht die Device.Flush() in dieser Datei sehen, aber ich vermute, dass es in der Telefonvorwahl ist.

Das Problem ist, dass Device.Flush() nicht synchron ist. Es funktioniert gut für leichte GPU-Lasten - die GPU endet, bevor der Lock/Unlock-Code beendet ist - aber für höhere Lasten ist das Rendern oft nicht beendet, was zumindest für einige Frames zu einem leeren Frame führt. Dies erscheint als Flimmern.

Das Schöne an Open Source ist, dass Sie den Code ändern können. Um dieses Problem zu überprüfen und bietet eine einfache (wenn hackish) Lösung, versuchen Sie die GPU ein bisschen mehr Zeit zu geben:

D3DImage.Lock(); 
Thread.Sleep(2); // 2ms 
D3DImage.AddDirtyRect(...); 
D3DImage.Unlock(); 

Wenn das reduziert oder eliminiert Ihr Flimmern, das Ihr Problem. Eine gründlichere Lösung, zumindest für Direct3D 10 oder 11, ist use query events as described in this question.

Das Problem bei der Verwendung von Windows Forms besteht darin, dass Sie WPF-Luftraumprobleme haben (die fehlende Möglichkeit, dass WPF-Objekte über das untergeordnete Fenster gezogen werden können). Airspace issues can be fixed, aber die Arbeit ist ein bisschen komplexer als die Bearbeitung des SharpDXElement.

1

Ich hatte das gleiche Problem, DeviceCreationFlags.SingleThreaded hat mir geholfen.

2

Das Problem ist nicht der Sperrmechanismus. Normalerweise verwenden Sie Present, um das Bild darzustellen. Present wartet bis alle Zeichnungen fertig sind. Mit D3DImage verwenden Sie nicht die Present() Methode. Anstatt zu präsentieren, sperren Sie, fügen Sie eine DirtyRect hinzu und entsperren Sie die D3DImage.

Das Rendering erfolgt asynchron, daher sind die Zeichenaktionen beim Entriegeln möglicherweise nicht bereit. Dies verursacht den Flimmereffekt. Manchmal siehst du Gegenstände, die halb gezeichnet sind. Eine schlechte Lösung (ich habe mit getestet) fügt eine kleine Verzögerung vor dem Entsperren hinzu. Es half ein wenig, aber es war keine saubere Lösung. Es war schrecklich!

Lösung:

ich mit etwas anderem weiter; Ich war mit MSAA (Antialiasing) expirimenting und das erste Problem, dem ich gegenüberstand, war; MSAA kann nicht auf der gemeinsamen dx11/dx9-Textur ausgeführt werden, daher entschied ich mich, eine neue Textur (dx11) zu rendern und eine Kopie an die gemeinsame dx9-Textur anzulegen. Ich knallte meinen Kopf auf den Tisch, denn jetzt war es anti-aliased und schnippelfrei !!

Sieht so aus, als würde die Kopieraktion warten, bis alle Zeichnungen fertig sind (natürlich), jetzt hilft es, die Zeichnung fertig zu stellen.

also eine Kopie der Textur zu erstellen:

DXDevice11.Device.ImmediateContext.ResolveSubresource(
    _dx11RenderTexture, 0, _dx11BackpageTexture, 0, ColorFormat); 

(_dx11BackpageTexture ist die gemeinsame Textur und _dx11RenderTexture ist die MSAA DX11 Textur) warten, bis die Wiedergabe bereit ist, und eine Kopie erstellen.

So habe ich von dem flackernden los ....

+0

BRILLIANT. Ich werde es versuchen. Seit Jahren von DX11/DX9 Flimmern geplagt und habe so viele verschiedene Hacks/Workarounds ausprobiert ... –