Tiled Map rendern



  • Um ehrlich zu sein, bin ich durch den GUI-Design Thread auf diese Frage gekommen, da ich das selbe Problem vermute.

    Annahme ich habe einen Bildschirm 800*600 und möchte dort eine TiledMap mit der Tilegröße 10px rendern also im Grunde 80 * 60 kleine Bildchen.

    Wie rendere ich das am geschicktesten?
    Einfach einen draw-Befehl für jedes Tile wäre wahrscheinlich wieder zu aufwendig, aber was mache ich sonst?



  • Das sollte eigentlich keine GPU jucken.

    Ansonsten, könnte sortieren nach Texturen was bringen?



  • TravisG schrieb:

    Das sollte eigentlich keine GPU jucken.

    Richtig, die GPU juckt das nicht, aber wenn jedes Quad mit einem eigenen Draw Call gezeichnet wird dann juckt das die CPU, und zwar gewaltig, genau aus dem Grund wurde Instancing erfunden und so 😉

    Am geschicktesten renderst du sowas indem du möglichst viele Quads in einen großen (dynamischen) Vertexbuffer packst und damit möglichst viel auf einmal renderst. Dabei verwendest du Tilesets (aka. Spritesheets) sodass möglichst viele Quads sich eine gemeinsame Textur teilen können und sortierst das ganze evtl. noch so gut es geht nach Shader (bzw. gemeinsamen Renderstates) und Textur um die Anzahl der Shader- bzw. Texture Switches und Draw Calls minimal zu halten. Dann juckt es weder GPU noch CPU 😉



  • dot schrieb:

    TravisG schrieb:

    Das sollte eigentlich keine GPU jucken.

    Richtig, die GPU juckt das nicht, aber wenn jedes Quad mit einem eigenen Draw Call gezeichnet wird dann juckt das die CPU, und zwar gewaltig, genau aus dem Grund wurde Instancing erfunden und so 😉

    80*60 draw calls jucken die CPU gewaltig? Woran liegt das? Sind die Buse zwischen Graka und CPU so geschwindigkeitsbegränzend?


  • Mod

    5k drawcalls duerften das limit von so ziemlich allen top titeln sein. das liegt am overhead der bei jeden drawcall entsteht, besonders falls dazu noch z.b. texturen usw. gewechselt werden. im drawcall selbst muss dann ziemlich viel verwaltungsaufwand gemacht werden, sowohl bei dx, als auch auf treiber seite als auch auf graka seite (dazu security level switchen und validierungen).

    stell es dir wie eine pkw fabrik vor, die schafft locker 1000 wagen am tag, aber nur weil es so ziemlich der selbe wagen ist. nehmen wir an dieselbe fabrig sollte einen polo, ein corsa, einen bmw M3 und ein wohnwagen produzieren. dafuer wuerden wochen vergehen, wenn du sie jedesmal umkonfigurieren musst.

    so ist das in etwa mit eine graka, ob du 1 dreieck oder 500dreiecke zeichnest in deinem drawcall, aendert so ziemlich garnichts an dem was sie an FPS schafft, in software waerst du beim zeichnen von dem 800x600 bild vermutlich genausoschnell fertig, selbst wenn du dafuer dann 2MB ueber PCIe uebertragen musst.



  • rapso schrieb:

    5k drawcalls duerften das limit von so ziemlich allen top titeln sein. das liegt am overhead der bei jeden drawcall entsteht, besonders falls dazu noch z.b. texturen usw. gewechselt werden. im drawcall selbst muss dann ziemlich viel verwaltungsaufwand gemacht werden, sowohl bei dx, als auch auf treiber seite als auch auf graka seite (dazu security level switchen und validierungen).

    stell es dir wie eine pkw fabrik vor, die schafft locker 1000 wagen am tag, aber nur weil es so ziemlich der selbe wagen ist. nehmen wir an dieselbe fabrig sollte einen polo, ein corsa, einen bmw M3 und ein wohnwagen produzieren. dafuer wuerden wochen vergehen, wenn du sie jedesmal umkonfigurieren musst.

    so ist das in etwa mit eine graka, ob du 1 dreieck oder 500dreiecke zeichnest in deinem drawcall, aendert so ziemlich garnichts an dem was sie an FPS schafft, in software waerst du beim zeichnen von dem 800x600 bild vermutlich genausoschnell fertig, selbst wenn du dafuer dann 2MB ueber PCIe uebertragen musst.

    Ja, so verstand ich das bisher auch. Mich wundert nur wirklich die kleine Zahl (wie du schätzt ~5000 Draw calls). Hört sich irgenwie merkwürdig an, wenn eine halbwegs aktuelle Graka ohne Probleme ... wieviel schaffen Grakas im Moment? Vielleicht knapp ne Milliarde Vertices / Sekunde (Ohne zusätzliche Shader etc. die Leistung wegnehmen)? ... rendern kann, aber dann so wenige Draw Calls verträgt. Aber wenn der Overhead wirklich so groß ist, ist das schon verständlich.

    Was könnte man dann in Shisha's Fall optimieren, wenn man irgendeine 2D-Lib verwendet, die keine Vertex Arrays unterstützt und intern einfach einzelne texturierte Quads in einzelnen draw calls zeichnet (und wenn man unbednigt so viele Tiles im Sichtfeld haben will (SFML,SDL etc.)?



  • dann solltest du darauf achten, dass du immer alles was gleich ist dirket hintereinanderweg zeichnest. Auch hier gilt ja wieder das Fabrikbeispiel:

    Die Fabrik ist am schnellsten, wnen du ihr den Auftrag gibst, 10000 Corsas zu produzieren. Gibst du stattdessen 10000 Aufträge für je 1 Corsa wird das zwar durch die Bürokratie langsamer, aber die Fabrik selbst muss nichts umstellen (checkt nur einmal durch, ob alles wie gewünscht aktiviert ist). Ansonsten solltest du immer so sortieren, dass die teuren Umstrukturierungen so selten wie möglich vorkommen und niemals die komplette Pipeline umgebaut werden muss.

    Man sollte sich dabei überlegen, dass die Grakahersteller die Dinge am Besten optimieren, die auch am Meistne durchgeführt werden müssen. Deswegen ist Vertexbuffer tauschen fast Gratis, während die Renderstates die man typischerweise nur einmal setzt (lightning, culling...) eher langsam sein werden.

    Ich glaube eine halbwegs aktuelle Aufteilung ist:

    VAO<Shadervariablen<Texturen<Shader<Rest



  • Mit 2D bist du schnell an der Füllrate der Graka. Das juckt die Graka sehr wohl. Weil es bleibt ja nicht bei 80x60 Quads, da kommt ja meist noch mehr dazu :D.
    Und wenn man jedes Quad einzeln zeichnet, dann kommen da nen haufen OpenGL Calls zusammen. Mein Projekt arbeitet derzeit unoptimiert so und das merkt man deutlich im Profiler. Die GL-Calls sind deutlich am Anschlag der Graka.

    Bin derzeit aber noch am grübeln wie man Sprites am besten Batcht bzw das in C++ am geschicktesten umsetzt, weil es müssen ja auch Shader gewechselt werden eventuell, andere States etc. Das macht mir derzeit ein wenig Kopfzerbrechen.

    Schritt 1:
    Textur-Atlas verwenden, damit elimierst du schonmal alle Texturwechsel. Hab hier vor nen paar Tagen nen sample mit nem Link zu nem Tool gepostet, vllt nutzt es dir was.

    Ich würde die Map einfach normal zeichnen und per ViewMatrix die selbe um 90° drehen. Das ist das einfachste. Da sparste dir nen haufen Berechnungen.

    VAO<Shadervariablen<Texturen<Shader<Rest

    Ja, das habe ich letztens auch so gelesen, wobei Shaderwechsel schneller sind anscheinend als Texturen.



  • Scorcher24 schrieb:

    Mit 2D bist du schnell an der Füllrate der Graka. Das juckt die Graka sehr wohl.

    Ja und nein.

    Was nicht funktioniert ist eine low-end Grafikkarte zu nehmen, und dann mit 10-fach Overdraw zu rendern, und dann noch 60fps rausbekommen wollen.

    Allerdings schafft z.B. eine Radeon 4650 noch 4-5fach Overdraw @ 1920x1080 mit 60fps. Wie viel besser das bei neueren, teureren Karten ist, kann ich leider nicht sagen (hängt ja vermutlich nur von der Speicherbandbreite ab, und ich weiss nicht wie viel sich da getan hat) 🙂

    Und mit 4-5fach sollte man schon recht weit kommen, wenn man ein wenig darauf achtet nicht sinnlos Performance zu verbraten. Also z.B. nicht lauter "leere" Tiles mit Alpha-Blending rendern, sondern diese Tiles einfach weglassen. Oder grosse Grafiken mit viel "leer" drinnen entsprechend aufteilen, so dass ein Grossteil der "leeren" Bereiche auch nicht gerendert wird.



  • Also ich hab ne 4850 HD von ATI. Ich hab keine FPS Probleme, aber die Anzahl der Calls merkt man schon auch bei wenig Quads. Aber nur im Profiler hehe. Aber da schaut es immer dramatischer aus als es wirklich ist :p.



  • Ja, man kann auch bei D3D auf die Debug-Runtime umschalten, dann sind Render-Calls auch gleich viel teurer als "in Wirklichkeit" 🤡


Anmelden zum Antworten