Die Engine funktioniert grundlegend anders als die der meisten anderen D3D11-Spiele. Ich bin mir ziemlich sicher, dass die eigentlich auf Low Level-APIs ausgelegt ist und D3D11 nachträglich irgendwie angeflanscht wurde, ohne dass man dabei großartig Rücksicht auf Performance genommen hat. Sowohl die Art und Weise, wie Multithreading fürs Rendering eingesetzt wird, als auch die etwas eigenwillige D3D11-Nutzung sprechen dafür.
Generell wird mit GPU-Culling gearbeitet, d.h. ein paar Compute Shader generieren Parameter für Draws (in erster Linie Vertex-Anzahl und -Offset) und filtern dabei unsichtbare Objekte heraus. Später wird das ganze dann mit indirekten Draw Calls gerendert. Das blöde: Die CPU weiß nicht, wie viele Objekte sichtbar sein werden, Dx11 bietet aber keine Möglichkeit, diese Information aus dem Grafikspeicher zu lesen. Also geht das Spiel auf Nummer Sicher und schickt teilweise über 100k Draw Calls
pro Frame an die GPU:
Von den ganzen Draw Calls rendern die meisten aber absolut
gar nichts. Also wirklich nichts. Schwer zu sagen, wie viele es genau sind, aber schätzungsweise 80% der Draw Calls haben einen Vertex Count von 0, wie im nächsten Screenshot auf der linken Seite zu sehen:
Das belastet nicht nur die CPU, sondern auch den Befehlsprozessor der GPU. Wenn der es nicht schafft, die Rechenwerke mit Arbeit zu füttern, weil fast keiner der Befehle irgendetwas rendert, langweilt sich zumindest zeitweise ein Großteil der GPU, und wenn dann auch noch die CPU es nicht schafft, schnell genug Befehle nachzuschieben, kommt es zu diesem merkwürdigen Verhalten, das ihr da beobachtet habt, wo das Heruntertakten der CPU trotz scheinbarer GPU-Limitierung zu Leistungseinbußen führt.
Für die CPU ist das aber auch problematisch. Die Engine ist zwar gewissermaßen schlau und vermeidet Zustandswechsel zwischen Draw Calls, also z.B. das Auswechseln von Texturen etc. (da kommt bei Dx11 der ganze CPU-Overhead her, von dem immer alle reden). Stattdessen erstellt das Spiel ein paar sehr große (8192x4096) Texturen, in denen ganz viele kleinere Texturen dicht gepackt sind, das sieht dann so aus:
Dennoch kosten 100k leere Draw Calls alleine gut und gerne 8ms CPU-Zeit auf meinem System, d.h. in so einer Situation sind schonmal gar nicht mehr als ~125 FPS möglich. Da im Spiel wie gesagt die meisten Draws nichts rendern, verschwendet das Spiel all diese Zeit für - genau -
absolut gar nichts. Ubisoft müsste sich da dringend etwas einfallen lassen - Origins nutzt die gleiche Technik, bringt es auf maximal 50-60k Draw Calls, läuft deutlich besser und sieht z.T. auch noch besser aus, und rendert im Endeffekt auch nicht weniger Objekte.
TL;DR die Engine ist zwar nicht komplett für den Arsch, aber auf dem PC sicherlich nicht so effizient wie sie sein könnte, wenn Ubisoft sich die Mühe gemacht hätte, einen Dx12- oder, Gott bewahre, Vulkan-Renderer einzubauen, was hier wahrscheinlich gar nicht mal so aufwändig wäre.
Aber eigentlich war das hier ein Benchmark-Thread, also hier mal die paar FPS, die meine RX 480 mit maximaler Grafik (außer Wolken) und 1080p-Auflösung unter Linux hinbekommt (Windows auch nur 10% schneller oder sowas). Spielen tu ich das ganze aber mit 30 FPS-Lock.