[DX9] sorry... Texturupload beschleunigen

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
Benutzeravatar
Schrompf
Moderator
Beiträge: 5040
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas
Wohnort: Dresden
Kontaktdaten:

[DX9] sorry... Texturupload beschleunigen

Beitrag von Schrompf »

Sorry, wirklich DX9. Bin immer noch nicht dazu gekommen, mal auf Vulkan umzubauen. Dort hätte man ja async transfers kriegen können.

Ich hab ein Spiel mit DX9. Das Spiel erzeugt on-the-fly Texturen und Meshes. Pro Frame z.b. einen Strauß 256er, 512er oder auch mal eins zwei 2048er. All diese Teile entstehen noch komplett auf der CPU, ich bündel sie auf einen 4096er Atlas und Jedes Frame erstelle ich eine neue Textur und befülle sie:

Code: Alles auswählen

d3dDevice->CreateTexture( breite, hoehe, 1, /*flags*/, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &mD3DTextur, NULL);
d3dDevice->CreateOffscreenPlainSurface( breite, hoehe, FMT, D3DPOOL_SYSTEMMEM, &tempsurf, nullptr);
tempsurf->LockRect( &rect, nullptr, D3DLOCK_DISCARD);
copyPixelData(dahin);
tempsurf->UnlockRect();
mD3DTextur->GetSurfaceLevel( 0, &zielSurface);
d3dDevice->UpdateSurface( tempsurf, &srcRect, zielSurface, &dstPoint);
zielSurface->Release();
tempsurf->Release();
So hab ich ne Textur, die ich dann an nem Sampler eines schlichten CopyShaders anbinde und an die eigentlichen Ziel-Positionen der Texturatlanten rendere.

Das Problem:

Code: Alles auswählen

TexturUpdate: 14 Fragmente mit MaxGröße 2048² auf 6 Ziel-Atlanten in 406.19ms
Mäh. Zugegeben, das ist ein Extrembeispiel, die Standardfälle sind 16x 128² in 70ms, aber das ist immer noch gesäßlangsam. Hat jemand ne Idee, wie ich das schneller kriegen könnte?
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Schrompf
Moderator
Beiträge: 5040
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas
Wohnort: Dresden
Kontaktdaten:

Re: [DX9] sorry... Texturupload beschleunigen

Beitrag von Schrompf »

Ich könnt einfach mal eine separate zielgenau große Temp-Textur für jeden einzelnen Transfer erstellen und so mit erhöhtem Overhead die Transfer-Menge minimieren.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [DX9] sorry... Texturupload beschleunigen

Beitrag von Krishty »

Knifflig. Ich locke die Texturen direkt, ohne Off-Screen Surface, da D3DLOCK_DISCARD bereits Synchronisierung vermeidet. Keine Ahnung ob schneller oder langsamer. Ich nehme an, dass das CreateTexture() nur beispielhaft den Kontext zeigt und du die Original-Resource überschreibst statt neue zu erstellen?
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
TomasRiker
Beiträge: 96
Registriert: 18.07.2011, 11:45
Echter Name: David Scherfgen
Wohnort: Hildesheim

Re: [DX9] sorry... Texturupload beschleunigen

Beitrag von TomasRiker »

Warum nicht direkt auf der Textur LockRect aufrufen? Wäre auf jeden Fall einen Versuch wert. D3DUSAGE_DYNAMIC nehmen.
Edit: Krishty war schneller :)
Benutzeravatar
Schrompf
Moderator
Beiträge: 5040
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas
Wohnort: Dresden
Kontaktdaten:

Re: [DX9] sorry... Texturupload beschleunigen

Beitrag von Schrompf »

DISCARD geht nicht, weil ich all die kleinen, mittleren und großen Texturen auf 1 bis x gigantischen Atlanten bündle. Gibt zwar NOOVERWRITE oder so, aber ich hab noch nie gesehen, dass das tatsächlich den Sync Stall vermieden hätte. Die trauen mir nicht :-(

Ich erstelle also wirklich ne neue Textur. Jedes Frame. Ich habe jedes Frame 0 bis x neue Images in allen möglichen Größen. Für die erstelle ich einen großen Atlas, frisch und neu nur für dieses Frame, pack die da alle drauf, und render dann von dieser Textur an die eigentlichen Stellen in den Atlanten. Die Neu-Erstellung einer Temp-Textur in jedem Frame vermeidet den GPU Sync. Ist aber leider arschlangsam. Wahrscheinlich weil ich das Ding pauschal 4096² groß mache, um genug Platz für alles zu haben.

Option also: ich mach ne Million einzelne Texturen für jede einzelne Quell-Textur, ich mach sie genau in der richtigen Größe, ich mach sie DYNAMIC und locke sie direkt. Hatte ich vorher schon, ging ganz gut... hm.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [DX9] sorry... Texturupload beschleunigen

Beitrag von Krishty »

Schrompf hat geschrieben: 10.11.2024, 21:30DISCARD geht nicht, weil ich …
Ah, verstehe – D3DLOCK_DISCARD kann nur die gesamte Textur überschreiben oder gar nichts, und du überschreibst ja Häppchen.

Ich versuche, herauszufinden, ob der Upload selber Flaschenhals ist oder das Erzeugen neuer Texturen. Ich weiß, dass Spiele in den 90ern Pools mit Textur-Objekten angelegt haben, um den Overhead von CreateTexture() zu vermeiden. Da ging es aber vor allem auch um VRAM-Fragmentierung, und ich dachte eigentlich, die sei seit der Virtualisierung in WDDM 1.1 (um Windows 7) Geschichte.

Kannst du das Timing von CreateOffscreenPlainSurface() und CreateTexture() getrennt von Unlock() und UpdateSurface() messen? Also Ressource-Verwaltung gegenüber tatsächlichem Upload?

Ich wollte dieses Wochenende meinen Windows-7-Rechner reparieren, damit ich endlich mal wieder eine D3D-9-Debug-Runtime habe. Natürlich ging das unter. Grmpf
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
TomasRiker
Beiträge: 96
Registriert: 18.07.2011, 11:45
Echter Name: David Scherfgen
Wohnort: Hildesheim

Re: [DX9] sorry... Texturupload beschleunigen

Beitrag von TomasRiker »

Die Doku sagt übrigens (Hervorhebung durch mich):
It is a good idea to create only one dynamic texture per format and possibly per size.
Nutzt du eigentlich auch MIP Maps? Dazu hat die Doku auch eine Warnung parat:
Dynamic mipmaps [...] are not recommended because of the additional overhead in locking every level. For mipmaps, D3DLOCK_DISCARD is allowed only on the top level. All levels are discarded by locking just the top level.
Ob das auch zutrifft, wenn man D3DUSAGE_AUTOGENMIPMAP benutzt?
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [DX9] sorry... Texturupload beschleunigen

Beitrag von Krishty »

Trifft definitiv auch zu; guter Fund. Die Mip-Map-Erzeugung sollte ja auf der GPU ablaufen und deshalb keinen CPU-Overhead zeigen; ich würde sie aber definitiv mal deaktivieren um zu prüfen, ob sich die Upload-Zeiten ändern.

Beachte, dass sich das Rendering stark verlangsamt, insbesondere mit großen Texturen. Ich hoffe, dein CPU-Timing-Code ist robust.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Schrompf
Moderator
Beiträge: 5040
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas
Wohnort: Dresden
Kontaktdaten:

Re: [DX9] sorry... Texturupload beschleunigen

Beitrag von Schrompf »

Jo, MipMaps hab ich für den Moment ausgeklammert, auch weil ich festgestellt habe, dass im Zuge irgendeines Umbaus in den letzten zehn Jahren mein Framework verlernt hat, in MipMaps zu rendern :-/ Sollte aber hier weniger kritisch sein als bei anderen Renderern, weil das Prinzip dieses On-The-Fly-Generierens auch dazu dient, die Daten immer genau im Detailgrad dazuhaben, der zur aktuellen Erscheinungsform auf dem Bildschirm passt.

Zum genauen Messen müsste ich das jetzt instrumentieren. Hab mal den VS-eingebauten Profiler mitlaufen lassen, aber der lässt sich anscheinend von den Fibers völlig verwirren, von 60k Samples hab ich überhaupt nur paar hundert im Profil gesehen. Der Rest war... sonstwo. Würde aber dazu passen, dass ich im VS-Debugger nur um 10% CPU Load beobachte. Sobald die Kamera still steht und alle GenJobs zur Ruhe kommen, rendert es in 3ms.

Ich probier mal die alte Version, wo ich einfach Texturen für jedes Schnipsel einzeln erzeuge und lösche. Sind dann tausende, aber wer kehrt? Geht ja erstmal, bis ich das alles auf Vulkan umschreibe.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
TomasRiker
Beiträge: 96
Registriert: 18.07.2011, 11:45
Echter Name: David Scherfgen
Wohnort: Hildesheim

Re: [DX9] sorry... Texturupload beschleunigen

Beitrag von TomasRiker »

Kommt eine reine GPU-basierte Erzeugung der Texturen in Betracht? Also mit einem (komplizierten) Shader direkt in die Textur rendern. Dann würdest du dir den teuren Transfer von CPU zu GPU sparen. Und wenn du dann noch eine zeitliche Verzögerung einbaust (Textur, die in Frame N gerendert wird, wird erst in Frame N+x benutzt, bis dahin noch die alte Version), vermeidest du Abhängigkeiten, wo die GPU warten muss.
Benutzeravatar
Schrompf
Moderator
Beiträge: 5040
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas
Wohnort: Dresden
Kontaktdaten:

Re: [DX9] sorry... Texturupload beschleunigen

Beitrag von Schrompf »

Ich bin noch nicht wieder dazu gekommen, irgendwas an dem Thema zu probieren.

Kurzfristig: ich will ne eigene kleine Temp-Textur für jeden Transfer zu den Texturatlanten ausprobieren. Damit übergebe ich dem Treiber den Stress, aber der müsste ja nach 20+ Jahren gut optimiert für sowas sein.

Langfristig: ja, da soll das alles auf der GPU laufen. Und aktuell ist das auch quasi ne NO-OP, was ich da in die Texturen rendere. Gedacht sind aber komplexe Operationen, die Mesh und Texturen gemeinsam verändern und jede Menge Kontext der umgebenden Szene einberechnen. Das krieg ich nicht im DX9-Shader hin, dafür brauch ich irgendwas Compute-fähiges. Und damit sind wir wieder bei der Vulkan-Portierung, die ich seit Jahren vor mir herschiebe.

Oder ich nehm DX11, das müsste alles viel einfacher sein und Computen kann ich da glaube ich auch. Kann ich? Weiß nicht. OpenGL könnte sicher alles, aber ich habe bisher nur Schlimmes über die Extension Hell gehört.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
dot
Establishment
Beiträge: 1745
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [DX9] sorry... Texturupload beschleunigen

Beitrag von dot »

Schrompf hat geschrieben: 12.11.2024, 11:24 Oder ich nehm DX11, das müsste alles viel einfacher sein und Computen kann ich da glaube ich auch. Kann ich? Weiß nicht. OpenGL könnte sicher alles, aber ich habe bisher nur Schlimmes über die Extension Hell gehört.
Portieren nach D3D11 wird auf jeden Fall um Größenordnungen einfacher als nach Vulkan. D3D11 ist effektiv eine saubere Version dessen, was D3D9 am Ende gerne gewesen wäre, mit ein paar Additions zur Pipeline. Und ja, hat basic Compute Support. OpenGL ist tot und war gegen Ende effektiv in Richtung D3D11 konvergiert und kann nicht wirklich mehr als D3D11 (abgesehen von einigen Extensions, an die du in D3D11 wenn überhaupt dann nur sehr mühsam rankommst).

Wenn Cross-platform dir egal ist und du einfach nur was Moderneres als D3D9 willst, dann ist D3D11 so ziemlich das Beste, was du dir nur wünschen könntest. Hat meiner Erfahrung nach unter Windows auch besseren Support als OpenGL.
Benutzeravatar
Schrompf
Moderator
Beiträge: 5040
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas
Wohnort: Dresden
Kontaktdaten:

Re: [DX9] sorry... Texturupload beschleunigen

Beitrag von Schrompf »

Hmja, Danke, dot, das passt zu meinem diffusen Wissen.

News an der Texturupload-Front: der Extremfall ist immer noch langsam, und irgendwann muss ich mal instrumentiert profilen und wirklich sehen, warum. Aber der Standardfall mit nem Dutzend 256er Texturen ist jetzt rasend schnell. So funktioniert's jetzt:

- Ich geh durch alle neuen Images durch und suche das Kleinste raus. Die sind immer Zweierpotenzen, immer quadratisch, immer minimal 128 und maximal 2048.
- Ich rechne aus, mit wievielen Kacheln dieser Größe ich alle Texturen transferiert kriege.
Optional: wenn das zuviele Kacheln sind, so dass die auf einer Zeile ne maximale Texturgröße sprengen würden, mach ich mehrere Zeilen
- Ich teile jedes neue Image in solche Kacheln auf und pack sie auf die Temp-Textur
- Ich gehe über jeden GPU-Texturatlas drüber und render dort hinein alle Kacheln, die auf diesem Atlas landen sollen

Ergebnis: es gibt jetzt eine passgenau großen Temp-Textur für jedes Frame. Tatsächlich x2, weil einmal Albedo und einmal World Normal. Und das braucht jetzt so maximal 120ms für ~6k² Bilddaten und ~2ms für das Standard-Dutzend an 128ern. Ruckt immer noch merklich im Extremfall, aber das alltägliche Leben im Dungeon fällt jetzt selten unter 60fps.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Antworten