2013-06-07 16 views
5

Sto eseguendo il porting di uno sparatutto a scorrimento che ho realizzato in XNA su Linux usando MonoGame. Quasi tutto è andato liscio, ma sto avendo un problema in un posto specifico con le chiamate a SpriteBatch.Draw() che paralizzano il framerate. Gran parte del gioco funziona bene senza intoppi. Disegna un buon numero di nemici e un gran numero di proiettili contemporaneamente senza alcun rallentamento. La parte che causa i fotogrammi rilasciati, tuttavia, è uno sfondo a scorrimento con livelli. Le sezioni di codice pertinenti sono qui.Monogame XNA basso framerate da poche chiamate Draw()

Level.cs:

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

Il "scrollingBackground" di cui sopra è un elenco di ScrollingBackgroundLayers, le sezioni rilevanti dei quali sono:

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); 
    } 
} 

Tutti di i problemi di framerate scompaiono non appena commento la chiamata a ScrollingBackgroundLayer.Draw(), quindi sembra che ci sia un grande suggerimento che il problema provenga dalla S Il tentativo di priteBatch di disegnare i livelli di scorrimento. Ovviamente, voglio capire perché questo sta accadendo. Ho esaminato altri problemi con SpriteBatches e la cosa più comune che ho trovato che potrebbe indicare una risposta è il fatto che viene creato un nuovo SpriteBatch ogni volta che viene modificata la trama, ma nemmeno l'impostazione di SpriteSortMode su Texture non ha apportato miglioramenti.

La diminuzione del framerate si verifica in una fase del gioco che ha 7 diversi ScollingBackgroundLayers, ognuno dei quali disegna una trama separata che è larga circa 700 pixel e alta 900 (ogni livello dovrebbe farlo non più di 2 volte per tenere conto di l'effetto di scorrimento). Mi sento come se mi dovessi perdere qualcosa di ovvio, perché il gioco a volte rende fino a 2-300 proiettili usando lo stesso identico sovraccarico, quindi altre 14 chiamate dovrebbero essere una goccia nel secchio. Si tratta semplicemente di un problema con il tentativo di disegnare trame troppo grandi per consentire a SpriteBatch di gestire in modo efficace? Questo non è un problema nella versione di Windows, quindi mi chiedo se non ci sia qualche soluzione specifica per la piattaforma a questo, o se l'implementazione di Draw di MonoGame è solo inefficiente. Qualsiasi commento sarebbe benvenuto.

sorgente completo per chi fosse interessato:

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

Edit: ho provato ad armeggiare con un po 'di più. Ho cambiato la chiamata a Draw() per garantire che il rettangolo di destinazione fosse uguale all'area disegnabile dello schermo, ma non ci sono stati cambiamenti evidenti. Ho sostituito la texture con una molto piccola e questo ha eliminato il ritardo, quindi penso che abbia qualcosa a che fare con la dimensione della texture.

Edit 2: Va bene, ho finito per mordere il proiettile e tagliare i livelli di trasparenza che stavo usando (come una sorta di non-pigro ragazzo). Ha risolto il problema, presumibilmente dal momento che non è più necessario rendere un numero enorme di pixel inutili, ma mi lascia ancora a chiedermi perché questo è solo un problema su Linux. Anche se per il momento ho risolto il mio problema, lo lascio questo per un po 'nel caso in cui qualcuno abbia qualche idea su cosa potrebbe causare la drastica differenza di prestazioni.

+1

Non riesco a ricordare i costi delle prestazioni per cose diverse, ma forzare la GPU a disegnare troppe texture ad alta risoluzione non è probabilmente una buona idea e qualcosa che dovresti essere in grado di progettare in un modo diverso. Se la memoria mi serve correggere quelle trame finirebbero per essere texture 1024 * 1024 (a causa della potenza di 2 requisiti e il rifacimento di quelle dimensioni durante il runtime) quando vengono inviate alla GPU. –

+0

Il problema in questo caso è che ogni immagine dello sfondo scorre a una velocità diversa o ha un diverso livello di trasparenza. Alcuni di questi potrei sicuramente tagliare e creare livelli che disegnano in aree più piccole dello schermo, ma alcuni di essi (per lo più trasparenti) non sono così facili. Non ero a conoscenza del fatto che la GPU ridimensionava comunque la potenza di due trame; forse li ridimensionerò e vedrò se cambierà qualcosa. Indipendentemente dalle ottimizzazioni che sto cercando di fare, sono davvero confuso perché questo problema non si verifica su Windows. – cmark89

risposta

2

In questa situazione, suggerirei di utilizzare uno shader, al fine di ottenere ciò. Vedrai le tue prestazioni salire alle stelle facendo così.Date un'occhiata al seguente:

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

Facendo in questo modo, sarà alleviare un sacco di utilizzo della CPU, e rendere la vostra GPU fare il grosso del lavoro.

Si potrebbe anche voler memorizzare le trame in potenza di 2, anziché 700x900. (fai qualcosa come 512x512). La tua pipeline grafica ha un incremento delle prestazioni in relazione alle trame che hanno una potenza di due.

+0

Sto esaminando questo, ma potrebbe essere eccessivo per quello che devo fare. Forse è solo perché gli shader mi terrorizzano. Ti risponderò quando avrò la possibilità di provare questo. – cmark89

+0

Questo non è eccessivo, ti assicuro che è molto semplice. Non hai nemmeno bisogno di sapere nulla degli shader per far funzionare tutto questo) – jgallant

+0

Non ho ancora provato a provarlo da quando ho finito con un semplice lavoro, ma poiché questa è l'unica risposta che sto marcando come accettato Sembra davvero una soluzione molto bella se riesci a far funzionare il file effetti (tangenzialmente, si tratta apparentemente di un calvario con l'attuale versione di MonoGame, che è il motivo per cui non l'ho provato). – cmark89