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
C-/C++-Quelltext |
|
1 2 3 4 |
struct RenderData { sf::VertexArray walls; // SFML-VertexArray für die Wände dieser Zeile std::set<GameObject*> objects; // Zeiger auf zu zeichnende GameObjects dieser Zeile }; |
Zitat von »Glocke«
Ich verwende einen std::vector<Cell*>als Repräsentant des zweidimensionalen Feldes
Zitat von »Glocke«
Nun gebe ich den RenderData-Pointer mit delete frei und gehe zur nächsten Zeile usw.
Zitat von »Glocke«
Nun zum "Sammeln der Renderdaten": Im Moment habe ich eine std::map<int, RenderData*>, wobei RenderData folgendes Strukt ist:
Zitat von »Glocke«
PS: ich bin gerade am überlegen, ob ein std::set pro RenderData gut ist...
Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Spiele Programmierer« (22.10.2014, 17:41)
Also die zentrale Frage die ich mir stellen würde wäre, wieviel zeichnest du wirklich? Wieviele Draw Calls und wieviele Polygone?
Wichtig wäre auch die Frage ob die Software wirklich an der CPU Performance in deinem Programm gebunden ist. Wenn du zuviele DrawCalls hast oder die Grafikkarte sonst überforderst, kannst du an den Datenstrukturen so viel optimieren wie du willst und es wird keinen Effekt auf die FPS in der Praxis haben, da hilft nur "weniger " zeichnen(Culling) oder eine effizientere API. (Also zum Beispiel "sf::VertexArray" anstatt einzellner Calls. Für besondere Methoden oder Anforderungen bietet sich auch an OpenGL direkt zu verwenden)
Profiling wäre auf jeden Fall eine Methode die dieses und mögliche andere Probleme aufgedeckt werden sollte.
Ein "std::vector<Cell>" wäre aus Gründen des Caches in der Praxis meistens effizienter, weil Zugriffe direkt erfolgen können und sequentiell sind. Außerdem entfällt Cacheverschwendung durch den Pointer.
Warum nicht auf dem Stack? (Nebenbei wenn dann Smart-Pointer...)
Eine "std::map" ist in den meisten Fällen nicht die effizienteste Wahl. In der Regel wird empfohlen, einen "std::vector" und dann zu sortieren.
[...]
"std::set" krankt an einem ähnlichen Problem wie die "std::map", also nein, mit sehr hoher Wahrscheinlichkeit eher nicht.
Bei den Datenstrukturen möchte ich ganz klar darauf hinweisen, dass man nicht zu viel auf das theoretische Laufzeitverhalten schauen schauen muss. Klar ist dass gut zum ersten Abschätzen und ein guter Anhaltspunkt. Gerade bei Datenstrukturen und Performance ist Cache mindestens genauso entscheidend.
SFML + Debug ist nicht das schnellste, checke mal was die FPS in der release version so machen.
Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Glocke« (23.10.2014, 10:05)
Meinst du mit "Debug version" und "Release version" die SFML - oder meinen Code?
Zitat von »Glocke«
Was meinst du mit "auf dem Stack?" Naja, ich weiß was ein Stack ist - nur gerade nicht was du genau meinst.
C-/C++-Quelltext |
|
1 2 3 4 |
void Something() { RenderData MyData; //oder genauso in einer "struct". Jetzt ist es einfach auf dem Programmstack. Das geht schneller. } |
Zitat von »Glocke«
D.h. die Berechnung "TilePos to ScreenPos" (um die Vertexpositionen zu bestimmen), werde ich einmal vorgerechnet ablegen.
Zitat von »Glocke«
Von Smart-Pointern habe ich bisher Abstand gehalten. Ich versuche möglichst viel mit Referenzen zu arbeiten - da wo es geht [...] Aber da ich
im Moment über Optimierungen nachdenke frage ich mich, was mir da Smart-Pointer bringen könnten? Afaik leichten Overhead .. oder übersehe ich was?
Zitat von »Glocke«
VIch überlege gerade, ob std::vector oder direkt std::forward_list.
Zitat von »Glocke«
Meinst du mit "Debug version" und "Release version" die SFML - oder meinen Code?
Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Spiele Programmierer« (23.10.2014, 13:32)
Community-Fossil
Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer
Ich würde testweise einfach mal das eine und das andere deaktivieren und die Performance messen
Wie berechnest du das? Ich glaube nicht, dass das der Flaschenhals ist. Berechnungen an sich sind in der Regel vergleichsweise schnell. Was Zeit kostet sind eher selten die blanken Berechnungen, sondern zum Beispiel die Speicherzugriffe oder (indirekte) Sprünge.
C-/C++-Quelltext |
|
1 2 3 4 5 6 |
sf::Vector2f WorldRenderer::toScreen(sf::Vector2f const & world_pos) const { return { (world_pos.x - world_pos.y) * this->tile_size.x / 2.f, (world_pos.x + world_pos.y) * this->tile_size.y / 2.f }; } |
"std::vector". Mit einem "std::vector" fährst du normalerweise immer am Besten. Bei "std::forward_list" hast du wieder eine verkettete Liste. Das heißt tausende Allokationen beim Erstellen und beim Durchgehen gibt es keine feste Reihenfolge im Speicher und eine Menge Pointer.
Beides. Die Debug Version solltest du wirklich nur zum debuggen verwenden. Die Geschwindigkeit ist nicht bloß niedrig sondern möglicherweise auch anders verteilt als im Release.
Zitat von »Glocke«
Ich wüsste da jetzt auch nicht was ich noch verbessern könnte - außer die Multiplikation durch einen entsprechenden Bitshift zu ersetzen.
Dein Prozessor kann Hundert Millionen bis Milliarden Floating Point Berechnungen pro Sekunde ausführen. Die paar Addition an der Stelle einmal pro Frame brauchen so extrem unverstellbar wahnsinnig wenig Zeit.
Übrigens: Bit Schiebereien gehen bei Gleitkommazahlen nicht. Das geh nur bei Integer. Dafür könnte man die Division mit einer Multiplikation mit 0.5 ersetzen
Du kannst auch ruhig den Debug-Modus verwenden. Deshalb gibt es den ja. Aber egal welche Maschine, zum Performance beurteilen oder testen, und auch wenn du dein fertiges Spiel tatsächlich verteilst oder selbst spielst willst, solltest du unbedingt in den Release Modus kompilieren.
Werbeanzeige