2013-06-07 51 views
5

Przesyłałem przewijaną grę strzelanki, którą zrobiłem w XNA, do Linuksa, używając MonoGame. Prawie wszystko poszło gładko, ale mam problem w określonym miejscu z wywołaniami do SpriteBatch.Draw() paraliżującego framerate. Większość gier działa dobrze bez żadnych problemów. Przyciąga dużą liczbę wrogów i dużą liczbę pocisków naraz bez spowolnienia. Częścią, która powoduje upuszczenie klatek, jest jednak przewijane warstwowo tło. Odpowiednie sekcje kodu znajdują się tutaj.Monogame XNA niska liczba klatek na sekundę z kilku wywołań funkcji Draw()

Level.cs:

public void Draw(SpriteBatch spriteBatch) 
{ 
    foreach (ScrollingBackgroundLayer sbl in scrollingBackground) 
    { 
     sbl.Draw(spriteBatch); 
    } 
} 

W "scrollingBackground" Powyżej znajduje się lista ScrollingBackgroundLayers, odpowiednie sekcje, które są:

ScrollingBackgroundLayers.cs:

Vector2[] scrollingBackgroundImages; 
public float DrawLayer; 

public ScrollingBackgroundLayer(GameScene newScene, Texture2D texture, float scrollSpeed, Color color) 
{ 
    layerColor = color; 
    layerSpeed = scrollSpeed; 
    layerTexture = texture; 
    thisScene = newScene; 

    Initialize(); 
} 

public void Initialize() 
{ 
    scrollingBackgroundImages = new Vector2[2]; 

    for (int i = 0; i < 2; i++) 
    { 
     scrollingBackgroundImages[i] = new Vector2(0, thisScene.ScreenArea.Height - (layerTexture.Height * i)); 
    } 
} 


public void Update(GameTime gameTime) 
{ 
    for (int i = 0; i < scrollingBackgroundImages.Length; i++) 
    { 
     scrollingBackgroundImages[i].Y += (float)gameTime.ElapsedGameTime.TotalSeconds * layerSpeed; 

     if (layerSpeed > 0 && scrollingBackgroundImages[i].Y >= thisScene.ScreenArea.Height) 
     { 
      scrollingBackgroundImages[i] = new Vector2(scrollingBackgroundImages[i].X, (scrollingBackgroundImages[i].Y - layerTexture.Height * 2)); 
     } 
     else if (layerSpeed < 0 && scrollingBackgroundImages[i].Y + layerTexture.Height <= 0) 
     { 
      scrollingBackgroundImages[i] = new Vector2(scrollingBackgroundImages[i].X, (scrollingBackgroundImages[i].Y + layerTexture.Height * 2)); 
     } 
    } 
} 

public void Draw(SpriteBatch spriteBatch) 
{ 
    foreach (Vector2 sb in scrollingBackgroundImages) 
    { 
     spriteBatch.Draw(layerTexture, sb, null, layerColor, 0f, Vector2.Zero, 1f, SpriteEffects.None, DrawLayer); 
    } 
} 

Wszystkie z problemy z framerate znikną, gdy tylko skomentuję wywołanie ScrollingBackgroundLayer.Draw(), więc wydaje się to być dość dużą wskazówką, że problem pochodzi z S priteBatch próbuje narysować przewijane warstwy. Oczywiście, chcę dowiedzieć się, dlaczego tak się dzieje. Przejrzałem kilka innych problemów z SpriteBatches, a najczęstszą rzeczą, jaką znalazłem, która mogłaby wskazywać na odpowiedź, jest fakt, że nowa opcja SpriteBatch jest tworzona za każdym razem, gdy zmienia się teksturę, ale nawet ustawienie SpriteSortMode na Texture nie dało żadnych ulepszeń.

Zmniejszenie liczby klatek na sekundę występuje na scenie gry, która ma 7 różnych arkuszy ScollingBackground, z których każda rysuje oddzielną teksturę o szerokości około 700 pikseli i wysokości 900 (każda warstwa powinna to zrobić nie więcej niż 2 razy, aby uwzględnić efekt przewijania). Czuję, że muszę przegapić coś oczywistego, ponieważ gra czasami renderuje aż 2-300 pocisków przy użyciu tego samego przeciążenia, więc kolejne 14 wywołań powinno być kroplą w wiadrze. Czy jest to po prostu problem z próbami narysowania zbyt dużych tekstur, aby SpriteBatch mógł skutecznie działać? To nie jest problem w wersji dla systemu Windows, więc zastanawiam się, czy nie ma jakiegoś rozwiązania tego typu związanego z platformą, lub czy implementacja Draw w MonoGame jest po prostu nieefektywna. Wszelkie opinie będą mile widziane.

Pełna źródło dla zainteresowanych:

Linux - https://github.com/cmark89/AsteroidRebuttal-Linux
Windows - https://github.com/cmark89/AsteroidRebuttal

Edit: Próbowałem majstrować przy nim nieco więcej. Zmieniłem wywołanie funkcji Draw(), aby upewnić się, że docelowy prostokąt jest równy obszarowi do rysowania na ekranie, ale nie było zauważalnej zmiany. Zamieniłem teksturę na bardzo małą i to wyeliminowało opóźnienie, więc myślę, że ma to coś wspólnego z rozmiarem tekstury.

Edycja 2: W porządku, skończyłem właśnie gryząc pocisk i przecinając warstwy przezroczystości, których używałem (jak jakiś nie-leniwy facet). Rozwiązał problem, prawdopodobnie dlatego, że nie musi już renderować ogromnej liczby bezużytecznych pikseli, ale wciąż zastanawia mnie, dlaczego jest to problem tylko w Linuksie. Chociaż na razie rozwiązałem mój problem, zamierzam zostawić to otwarte na chwilę, na wypadek gdyby ktoś miał wgląd w to, co może powodować drastyczną różnicę w wydajności.

+1

Naprawdę nie pamiętam kosztów wydajności dla różnych rzeczy, ale zmuszając GPU do narysowania, że ​​wiele tekstur o wysokiej rozdzielczości nie jest prawdopodobnie dobrym pomysłem i czymś, co powinieneś być w stanie zaprojektować w inny sposób. Jeśli pamięć mnie obsłuży, tekstury te będą w końcu teksturami 1024 * 1024 (ze względu na potęgę 2-wymagania i przeróbkę na ten rozmiar w czasie wykonywania), kiedy zostaną wysłane do GPU. –

+0

Problem w tym przypadku polega na tym, że każdy obraz tła przewija się z inną prędkością lub ma inny poziom przezroczystości. Niektóre z nich mogę zdecydowanie posiekać i stworzyć warstwy, które przyciągają mniejsze obszary ekranu, ale niektóre z nich (głównie warstwy przezroczystości) nie są tak łatwe. Nie wiedziałem, że GPU zmieniło i tak brak mocy dwóch tekstur; może zmienię je i zobaczę, czy coś to zmieni. Niezależnie od optymalizacji, które zamierzam podjąć, jestem bardzo zdezorientowany, dlaczego ten problem nie występuje w systemie Windows. – cmark89

Odpowiedz

2

W tej sytuacji proponuję użyć zamiast tego shadera, aby to osiągnąć. W ten sposób zauważysz gwałtowny wzrost wydajności.Spójrz, co następuje:

http://www.david-gouveia.com/scrolling-textures-with-zoom-and-rotation/

Robi to w ten sposób, będzie łagodzić wiele użycie CPU, GPU i dokonać wykonać większość pracy.

Możesz również chcieć przechowywać tekstury w potęgach 2, zamiast 700x900. (zrób coś w stylu 512x512). Rurka graficzna ma zwiększoną wydajność w odniesieniu do tekstur o potędze dwóch.

+0

Rozważam to, ale może to być przesada w stosunku do tego, co muszę zrobić. Może dlatego, że cieniści mnie przerażają. Wrócę do ciebie, kiedy będę miał szansę spróbować. – cmark89

+0

To nie jest przesada, zapewniam cię, że to bardzo proste. Nie musisz nawet nic wiedzieć o shaderów, aby to działało;) – jgallant

+0

Nie próbowałem tego, ponieważ skończyłem po prostu używając prostszej pracy, ale ponieważ jest to jedyna odpowiedź, którą zaznaczam jak zaakceptowano. Rzeczywiście wygląda na to, że jest to bardzo dobre rozwiązanie, jeśli uda ci się uruchomić plik z efektami (tak na marginesie, jest to jakaś próba z obecną wersją MonoGame, dlatego nie próbowałem go). – cmark89