Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

LeBusch

Frischling

  • »LeBusch« ist der Autor dieses Themas

Beiträge: 81

Beruf: Student B.Sc. Informatik

  • Private Nachricht senden

1

16.11.2013, 21:10

SlimDX - Performance beim Zeichnen von Hintergrundkachel

Moin,

Ich bin momentan dabei, mein RPG statt in VB.Net in C# zu schreiben und statt GDI+ SlimDX bzw. Direct2D zu nutzen. Anfangs war ich begeistert, dass die Framerate plötzlich zehn bis zwanzig Mal höher war - jedoch bin ich jetzt an einem Punkt angelangt, an dem sie (für mich unbegreiflicherweise) sogar niedriger ist. Jedoch verstehe ich beim besten Willen nicht, warum. Hier die entsprechenden Code-Fetzen:

Alt:

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
'Hintergrundtile:
For i0 = 0 To currentmap.width

 For i1 = 0 To currentmap.height

  With currentmap.backgroundtile

   G.DrawImageUnscaled(.img, i0 * 16 - inplayer.position.X + 10 * 16, i1 * 16 - inplayer.position.Y + 7 * 16)

  End With

 Next

Next


Neu:

C#-Quelltext

1
2
3
4
5
6
7
8
9
10
11
//Hintergrund-Tile
for (int i1 = 0; i1 < inmap.GetWidth(); i1++)
{
 for (int i2 = 0; i2 < inmap.GetHeight(); i2++)
 {
     rendertarget.DrawBitmap(inmap.GetBGTile().GetSprite(), 
                    new Rectangle((i1 * 16) - (inplayer.GetPosition().GetX() * 16) + ((res.Width / 2) - 16),
                    (i2 * 16) - (inplayer.GetPosition().GetY() * 16) + ((res.Height / 2) - 16),
                    16, 16));
 }
}


Mit GDI+ erreiche ich (bei 336x224px) ~200Fps, mit Direct2D erreiche ich (von der Auflösung unabhängig) ~140Fps. Daher gehe ich von einer CPU-seitigen Limitierung aus. Rendere ich die Hintergrundkacheln nicht, schwanken die Fps zwischen 3000 und 4000. Warum aber ist die CPU durch zwei simple Schleifen vollkommen ausgelastet? Dadurch, dass ich kein GDI+ mehr nutze, sollte die CPU sich doch eigentlich eher einen Schnupfen holen? Eventuell hat ja jemand einen kleinen Hinweis für mich.

Beste Grüße,
LeBusch

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »LeBusch« (16.11.2013, 21:24) aus folgendem Grund: Kleinen Copy&Paste-Fehler beim C#-Code überarbeitet.


BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

2

16.11.2013, 21:31

Solange Du der CPU sagst sie soll was tun, solange tut sie auch was. Wenn sie nichts tun soll, musst Du auch dafür sorgen, dass sie solche Zeit zugesprochen bekommt.

Direct2D solltest Du übrigens nicht mehr verwenden.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

LeBusch

Frischling

  • »LeBusch« ist der Autor dieses Themas

Beiträge: 81

Beruf: Student B.Sc. Informatik

  • Private Nachricht senden

3

16.11.2013, 21:54

Solange Du der CPU sagst sie soll was tun, solange tut sie auch was. Wenn sie nichts tun soll, musst Du auch dafür sorgen, dass sie solche Zeit zugesprochen bekommt.
Das Problem ist ja eben gerade, dass sie meiner Meinung nach mehr Idle-Zeit haben sollte, da das eigentliche Rendering ja größtenteils über die GPU statt über die CPU läuft. Daher müsste die "neue" Schleife der Theorie nach schneller als die "alte" sein. Ich stelle mir das ganze so vor:

Altes Verfahren:
CPU: Schleife -> Rendering -> Schleife -> ...
GPU: Leerlauf -> Leerlauf -> Leerlauf -> ...

Neues Verfahren:
CPU: Schleife -> Leerlauf -> Schleife -> ...
GPU: Leerlauf -> Rendering -> Leerlauf -> ...

Warum aber wird die CPU im Falle der "neuen" Schleife stärker beansprucht? Das ist es, was ich nicht nachvollziehen kann.

Direct2D solltest Du übrigens nicht mehr verwenden.
Ich hatte bisher nur gelesen, dass man DirectDraw nicht mehr benutzen soll, weil es veraltet ist. Weshalb sollte man D2D denn nicht mehr verwenden?

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

4

16.11.2013, 22:47

Wieso sollte die CPU in den Leerlauf schalten, wenn Du ihr die ganze Zeit etwas zu tun gibst?

Vergiss den Kommentar zu Direct2D, ich hatte DirectDraw im Kopf ;)
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »BlueCobold« (16.11.2013, 22:56)


dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

5

16.11.2013, 22:53

Zeichnest du in dieser Schleife immer das gleiche Sprite oder sind das alles verschiedene Sprites, die da an DrawBitmap() übergeben werden?

LeBusch

Frischling

  • »LeBusch« ist der Autor dieses Themas

Beiträge: 81

Beruf: Student B.Sc. Informatik

  • Private Nachricht senden

6

17.11.2013, 09:04



Wieso sollte die CPU in den Leerlauf schalten, wenn Du ihr die ganze Zeit etwas zu tun gibst?

Vergiss den Kommentar zu Direct2D, ich hatte DirectDraw im Kopf ;)
Schon vergessen ;) Da alles in einem Thread abläuft, muss die CPU auf die GPU warten - so stelle ich mir das zumindest vor. Für den Zeitraum, in dem die GPU mit D2D.Drawbitmap() beschäftigt ist, müsste die CPU ja quasi arbeitslos sein.



Zeichnest du in dieser Schleife immer das gleiche Sprite oder sind das alles verschiedene Sprites, die da an DrawBitmap() übergeben werden?
In dieser Schleife ist es immer das gleiche Sprite. Diese Ebene soll den Boden darstellen, auf den dann im nächsten Schritt der Spieler und alle anderen Tiles gezeichnet werden.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

7

17.11.2013, 09:45

Die CPU wartet aber nicht, bis die GPU mit ihrer Operation fertig ist. Dein Programm auf der CPU muss lediglich solange warten, bis der Treiber (auch auf der CPU) die Befehle an die GPU verarbeitet hat. Erst dann bekommt dein Programm-Thread die Kontrolle vom Kernel-Thread zurück. Die GPU arbeitet dann aber parallel zur CPU. Daher hat deine CPU auch immer was zu tun. Sie wartet nirgends. Wie gesagt, dafür müsstest Du schon irgendwo auch tatsächlich warten. Z.B. darauf, dass alle Befehle von der GPU ausgeführt wurden, auf einen VSync oder sonst auf irgendwas. Machst Du aber nicht. Daher volle Auslastung.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

LeBusch

Frischling

  • »LeBusch« ist der Autor dieses Themas

Beiträge: 81

Beruf: Student B.Sc. Informatik

  • Private Nachricht senden

8

17.11.2013, 10:25

Okay, mein VSync für Arme habe ich jetzt mal aus meiner alten VB-Version übernommen.

C#-Quelltext

1
2
3
4
5
6
7
8
9
private DateTime nexttime = DateTime.Now;

[...]

if (DateTime.Now >= nexttime) {
 //rendern
 [...]
 nexttime = DateTime.Now.AddMilliseconds(Convert.ToInt32(1000 / frequency));
}

Jetzt sind meine FPS auf 60 begrenzt und die CPU hat entsprechend Ruhezeiten. Trotzdem frage ich mich, wieso

Quellcode

1
   G.DrawImageUnscaled(.img, i0 * 16 - inplayer.position.X + 10 * 16, i1 * 16 - inplayer.position.Y + 7 * 16)
schneller ist, als

C#-Quelltext

1
2
3
4
                            rendertarget.DrawBitmap(inmap.GetBGTile().GetSprite(),
                                new Rectangle((i1 * 16) - (inplayer.GetPosition().GetX() * 16) + ((res.Width / 2) - 16),
                                    (i2 * 16) - (inplayer.GetPosition().GetY() * 16) + ((res.Height / 2) - 16),
                                    16, 16));

Überfordere ich CPU und GPU mit den etlichen kleinen Befehlen? Ich habe mal ein klein wenig herumexperimentiert: Ändere ich die Größe des Levels von 50x50 auf 25x25, erreiche ich ~1200 statt 140 FPS. Die deutliche FPS-Steigerung kann ich nachvollziehen, schließlich müssen GPU und CPU knapp 2000 Befehle pro Durchlauf weniger verarbeiten. Warum aber zeigt sich GDI+ von der Menge der Tiles weniger beeindruckt als DX? Ist eventuell die Schnittstelle zwischen CPU und GPU der Flaschenhals? Wenn ja, wie könnte ich das Zeichnen der Hintergrundtiles effizienter lösen? Ich habe bereits versucht, nur die Tiles zu rendern, die auch im Sichtfeld liegen. Durch die zusätzlichen Abfragen sinken die FPS aber noch weiter.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

9

17.11.2013, 10:40

Ich würde mal vermuten, dass GDI+ viele Befehle zu wenigen Calls zusammenfasst, während Du sie mit DX direkt in den Treiber jagst und damit deutlich mehr Kontext-Wechsel erzwingst.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

LeBusch

Frischling

  • »LeBusch« ist der Autor dieses Themas

Beiträge: 81

Beruf: Student B.Sc. Informatik

  • Private Nachricht senden

10

17.11.2013, 11:15

Vielen Dank für deine Hilfe! Ich habe das Problem jetzt gelöst, indem ich beim Laden der Map mit GDI+ ein großes Bitmap ((16 * Breite) x (16 * Höhe)) erstelle, auf dieses dann die Hintergrundkachel (Breite * Höhe) Mal zeichen lasse, dieses GDI+-Bitmap in ein D2D-Bitmap konvertiere und dann nur noch das D2D-Bitmap zeichnen lasse. Dadurch habe ich jetzt knapp 3500Fps :) Habe ich das eigentlich richtig verstanden, dass das Zeichnen des Hintergrundes bzw. das Laden und Zuschneiden der Bitmaps ohne GDI+ und anschließendes Konvertieren nicht möglich ist? Denn bisher bin ich noch auf keine bessere Lösung gestoßen, halte aber auch die Lösung mit Zwischenschritt über GDI+ bei Weitem nicht für optimal.

Werbeanzeige