2015-01-12 24 views
5

Tamamen çok yakın olan bir SharpDX projem var. Etkileşim için Kinect kullanır. Bu nedenle projem hem Kinect bölgesi hem de KinectUserViewer nesnesi için WPF kullanıyor. SharpDX şimdiye kadar her şey için harika çalıştı, ancak, direct3D'yi ağır bir şekilde kullanan programın belli bir bölümüne geldiğinde, titreme başlar. Bu açıkça D3Dimage'in (MainWindow.xaml'deki SharpDXElement tarafından kullanılan) "temelde kırılmış ve WPF'de verimli D3D oluşturma için uygun olmayan" [1] olması gerçeğine bağlı. WPF elemanlarımı tutmanın ve direct3D ile titremenin bir yolu var mı?SharpDXElement alternatifine ihtiyacınız var. SharpDX WPF titremesinin geçici çözümü

+0

Eğer bazı ilgili kod gösterebilir misiniz? Böyle bir soruyu cevaplarken nerede olduğunuzu görmeye muazzam yardımcı olur. – rfornal

+0

15000'den fazla kod satırı vardır. İlgili kodu bulmak zor. Çizim ve güncelleme döngüsü için toolkit.game sınıfını kullanır. Öncelikle spritebatch kullanıyorum ama bunun bir kısmı, söz konusu kısım da dahil olmak üzere hem xna hem de direct3D kullanıyor. Özellikle yardımcı olabileceğini düşündüğünüz bir kısım var mı? – Asor

+0

Say, bağlantınıza bir baktım ve teklifinizin içeriğine baktığımda, bir Windows Formu kullanarak sınırlı bir çözümden bahsettiler. Geçici çözümü anladım, bu aslında D3DImage değiştirme alanında bir Windows Formunu barındıracaktı - ve sadece * alanın XAML öğelerini kullanamayacağını düşünüyorum. Bu senin işine yarar mıydı? Yoksa geçici çözümün doğası hakkında bir şey mi eksik? –

cevap

5

Yanıp sönme, D3DImage'ın ön arabelleğe kopyalamaya çalışmasından önce, GPU'nun çerçeveyi oluşturmayı bitirmediğini gösterir. Bu, WPF'de kolaylıkla meydana gelebilir çünkü WPF, bir çerçeve oluşturmak için bir takas zincirine standart bir sunum mekanizmasını kullanmaz. - O dosyada Device.Flush() görmüyorum ama çağıran kodunda olduğundan şüpheleniyorsanız SharpDXElement.InvalidateRender ardından en azından desen var

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

: Bunun yerine, en kodunuz aşağıdaki gibi kullanır.

Sorun şu ki, Device.Flush() senkronize değil. Hafif GPU yükleri için iyi çalışıyor - Kilitleme/Kilit açma kodunun bitiminden önce GPU tamamlanıyor - ancak daha ağır yükler için bu işlem çoğu zaman işlenmeyi tamamlamamıştı ve sonuçta bazı kareler için boş bir çerçeve ortaya çıkıyordu. Bu titreşimsiz görünür.

Açık kaynak kodunun güzel tarafı, kodu değiştirebilmenizdir. Bu sorunu doğrulayıp kolay (eğer hackish) çözümü sağlamak için, gpu biraz daha fazla zaman vererek deneyin:

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

o azaltan veya titremeyi önlüyor, bu senin sorunun. Direct3D 10 veya 11 için en kapsamlı çözüm, use query events as described in this question.

Windows Forms'ı kullanmayla ilgili sorun, WPF airspace sorunları ile sonuçlanır (WPF öğelerinin alt pencerenin üzerine çizilememesi). , ancak bu çalışma SharpDXElement'i düzenlemekten biraz daha karmaşıktır.

1

Aynı problem vardı, DeviceCreationFlags.SingleThreaded bana yardım etti.

2

Sorun Kilitleme mekanizması değildir. Normalde görüntüyü sunmak için Present kullanın. Present, tüm çizim hazır olana kadar bekleyecektir. D3DImage ile Present() yöntemini kullanmıyorsunuz. Sunum yerine, bir DirtyRect ekleyerek kilitlenir ve D3DImage kilidini açarsınız.

Görüntü oluşturma, senkronize olmadığında, böylece kilidi açtığınızda, çizim eylemleri hazır olmayabilir. Bu titreşim etkisine neden oluyor. Bazen yarısı çekilen eşyaları görürsünüz. (test ettim) zayıf bir çözüm, kilidi açmadan önce küçük bir gecikme ekliyor. Biraz yardımcı oldu, ama temiz bir çözüm değildi. Berbattı!

Çözüm: başka bir şey ile devam

; MSAA (antialiasing) ile deneyimledim ve karşılaştığım ilk problem; MSAA, dx11/dx9 paylaşılan dokusunda yapılamaz, bu yüzden yeni bir dokuya (dx11) oluşturmaya ve dx9 paylaşılan dokusuna bir kopya oluşturmaya karar verdim. Kafamı masaya çarptı, çünkü artık anti-aliased VE flicking-free!

Thr kopya eylemi, tüm çizimler hazır olana kadar bekler (tabi ki) artık çizimin tamamlanmasına yardımcı oluyor.

Yani, doku bir kopyasını oluşturarak:

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

(_dx11BackpageTexture paylaşılan doku ve _dx11RenderTexture MSAA DX11 doku olan) render hazırdır ve bir kopyasını oluşturur kadar bekleyecektir.

Bu benim titremesi kurtuldum nasıl ....

+0

BRILLIANT. Bunu denemek için gidiyor. Yıllarca yanıp sönen DX11/DX9 tarafından sıkıntıya düştünüz ve çok sayıda farklı şifre/çözüm denemeye çalıştık ... –