2009-04-30 10 views
7

Utworzono formant WPF (dziedziczący z FrameworkElement), który wyświetla kafelkową grafikę, którą można przesuwać. Każdy kafelek ma 256x256 pikseli przy 24 bpp. Nadpisałem OnRender. Tam ładuję nowe płytki (jako BitmapFrame), a następnie rysuję wszystkie widoczne kafelki za pomocą drawingContext.DrawImage.Wydajność renderowania WPF z BitmapSource

Teraz, gdy jest więcej niż kilka nowych płytek na cykl renderowania, liczba klatek na sekundę spada z 60 fps do zera na około sekundę. Nie jest to spowodowane ładowaniem obrazów (co zajmuje milisekundy) ani rysowaniem DrawImage (co nie zabiera wcale czasu, ponieważ wypełnia jedynie pewną pośrednią strukturę danych renderowania).

Domyślam się, że wątek renderowania sam się dławi, ilekroć otrzyma dużą liczbę (~ 20) nowych instancji BitmapSource (czyli tych, które nie zostały jeszcze buforowane). Albo spędza dużo czasu konwertując je do jakiegoś wewnętrznego formatu kompatybilnego z DirectX, albo może to być problem z buforowaniem. Nie może zabraknąć pamięci RAM wideo; Perforator pokazuje szczyty poniżej 60MB, mam 256MB. Ponadto, Perforator mówi, że wszystkie cele renderowania są przyspieszane sprzętowo, więc to też nie może być.

Wszelkie spostrzeżenia są mile widziane!

góry dzięki

Daniel

@RandomEngy:
BitmapScalingMode.LowQuality zmniejszył problemu trochę, ale nie pozbyć się go. Już ładuję płytki w zamierzonej rozdzielczości. I nie może to być sterownik graficzny, który jest aktualny (Nvidia).
Jestem trochę zaskoczony tym, że skalowanie zajmuje tyle czasu. Sposób, w jaki to zrozumiałam, bitmapę (niezależnie od jej rozmiaru) jest ładowana jako tekstura Direct3D, a następnie skalowana sprzętowo. W rzeczywistości, po renderowaniu bitmapy po raz pierwszy, mogę zmienić jej rotację i skalę bez żadnych dalszych zawieszania.

Odpowiedz

3

To nie tylko duża liczba zdjęć. Wystarczy jeden duży obraz, aby pomieścić renderowanie, dopóki nie zostanie załadowany, a to może być dość zauważalne, gdy wymiary obrazu zaczynają wzrastać w tysiącach.

Zgadzam się z Tobą, że prawdopodobnie jest to wątek renderowania: wykonałem test, a wątek interfejsu użytkownika wciąż był szczęśliwy, wysyłając wiadomości, podczas gdy opóźnienie renderowania miało miejsce od próby wyświetlenia w pełni buforowanego obrazu bitmapowego.

To musi być jakiś rodzaj konwersji lub przygotowania na obrazie, tak jak spekulowałeś. Próbowałem złagodzić to w mojej aplikacji przez "renderowanie", ale ukrywając obraz, a następnie ujawniając go, gdy muszę go pokazać. Jest to jednak mniej niż idealne, ponieważ renderowanie i tak zawiesza się.

(Edit)

Niektóre Kontynuacja: Po dyskusji na temat aliasu MS WPF znalazłem, co było przyczyną opóźnień. Na moim komputerze z systemem Windows Server 2008 było to połączenie starych sterowników wideo, które nie obsługują nowego modelu sterownika WDDM i opóźnienia w zmianie rozmiaru obrazu.

Jeśli rozmiar obrazu źródłowego różni się od rozmiaru wyświetlania, spowoduje to opóźnienie renderowania przed wyświetleniem obrazu. Domyślnie obraz jest ustawiony na najwyższą jakość, ale można zmienić opcje skalowania renderowania, wywołując RenderOptions.SetBitmapScalingMode(uiImage, BitmapScalingMode.LowQuality);. Kiedy to zrobiłem, tajemnicze zamrożenie przed wyświetleniem obrazu zniknęło. Alternatywą, jeśli nie lubisz spadku jakości w skalowaniu, jest załadowanie BitmapImage przy DecodePixelWidth/Height równym rozmiarowi, w którym będzie wyświetlane. Następnie, jeśli załadujesz BitmapImage na wątku w tle, nie powinieneś mieć opóźnienia w jego wyświetlaniu.

0

Też spróbuj;

/* ivis is declared in XAML <Image x:Name="iVis" UseLayoutRounding="True" SnapsToDevicePixels="True" /> */ 

iVis.Stretch = Stretch.None; 
RenderOptions.SetBitmapScalingMode(iVis, BitmapScalingMode.NearestNeighbor); 
RenderOptions.SetEdgeMode(iVis, EdgeMode.Aliased); 
VisualBitmapScalingMode = BitmapScalingMode.NearestNeighbor; 
iVis.Source = **** your bitmap source **** 

miałem pewne problemy z wydajności podczas korzystania z ogromnej ilości „A” kolor kanału, czekając aż po obraz oddał do skalowania działał znacznie lepiej dla mnie.

Również, jak powiedziałeś, używając kafelkowej grafiki?

Zwykle używasz TileBrush, aby po prostu ustawić jako pędzel na swoim FrameworkElement. Jeśli animujesz je lub dynamicznie dodajesz nowe, możesz wygenerować pędzle, a następnie zastosować je do obiektu, gdy będziesz jeździł ręcznie, pamiętaj, aby je zamrozić, jeśli możesz. Ponadto VisualBitmapScalingMode jest właściwością dowolnego Visual.