Ich neige oft dazu, viel vorzeitige Optimierung zu betreiben, wenn ich mich mit Grafiken beschäftige. Es gibt einige Prinzipien, denen ich immer zu folgen versuche:
- Halten Sie die Anzahl der D3D-Komponenten auf ein Minimum.(Renderzustände, Puffer, Shader usw.)
- Binden Sie Komponenten nur, wenn dies unbedingt erforderlich ist.(Nicht schon gebunden usw.)
- Spezialisieren Sie die Komponenten so weit wie möglich.(Setzen Sie nur die erforderlichen BindFlags usw.)
Dies führte mich dazu, sehr aufwendige Wrapper für die Verwaltung der erstellten Komponenten und des aktuellen Rohrleitungsstatus zu erstellen. Dies verbraucht nicht nur viel meiner wertvollen Entwicklungszeit, sondern erhöht auch die Komplexität.
Und das Schlimmste von allem: Ich weiß nicht einmal, ob sich die Mühe lohnt.
Einige meiner Optimierungsüberlegungen sind möglicherweise bereits auf einer niedrigeren Ebene implementiert, und ich repliziere sie nur, wodurch zusätzlich Zeit für die CPU verschwendet wird. Andere Überlegungen können völlig unnötig sein, da die Auswirkung auf die Leistung vernachlässigbar ist.
Meine Fragen sind also:
- Welche der oben genannten Richtlinien sind gültig und in welchem Umfang sollte ich sie befolgen?
- Wie geht die GPU mit Statusänderungen um?
- Was passiert, wenn ich einen Status ändere, der nie verwendet wird? (Es wird kein Draw Call getätigt, solange es aktiv ist.)
- Was sind die tatsächlichen Leistungseinbußen beim Binden der verschiedenen Komponenten?
- Welche anderen Leistungsüberlegungen sollten gemacht werden?
Bitte sagen Sie mir nicht nur, dass ich mich nicht um die Leistung kümmern sollte, bis ich die tatsächlichen Grenzen erreicht habe. Während dies aus praktischer Sicht offensichtlich zutrifft, interessiert mich hauptsächlich die Theorie. Ich muss irgendwie dem Drang entgegenwirken, das optimale Grafik-Framework zu erstellen erstellen, und ich glaube nicht, dass ich das mit der üblichen "Vorlesung zur vorzeitigen Optimierung" tun kann.
Komponenten verwalten
Ich schreibe derzeit DirectX 11-Anwendungen in C # mit SlimDX als verwaltetem Wrapper. Es ist ein Wrapper auf sehr niedriger Ebene und meine aktuelle Abstraktion baut darauf auf.
Die Verwendung einer Direct3D-Abstraktion bietet einige offensichtliche Vorteile. Das Einrichten der Umgebung, das Laden von Shadern, das Festlegen von Konstanten und das Zeichnen eines Netzes ist viel einfacher und erfordert viel weniger Code. Da es die Erstellung und Entsorgung der meisten Komponenten verwaltet, können sie überall automatisch wiederverwendet werden, und ich vermeide fast vollständig Speicherlecks.
- Wie verwalten Sie normalerweise alle Grafikkomponenten und Ressourcen?
- Können Sie verwaltete Wrapper empfehlen, die etwas Ähnliches wie mein Beispiel unten tun?
Hier ist ein Beispiel meiner aktuellen Implementierung. Ich bin sehr zufrieden mit der Schnittstelle. Es hat genug Flexibilität für meine Bedürfnisse und ist sehr einfach zu bedienen und zu verstehen:
// Init D3D environment
var window = new RenderForm();
var d3d = new Direct3D(window, GraphicsSettings.Default);
var graphics = new GraphicsManager(d3d.Device);
// Load assets
var mesh = GeometryPackage.FromFile(d3d, "teapot.gp");
var texture = Texture.FromFile(d3d, "bricks.dds");
// Render states
graphics.SetViewports(new Viewport(0, 0, 800, 600);
graphics.SetRasterizer(wireFrame: false, culling: CullMode.Back);
graphics.SetDepthState(depthEnabled: true, depthWriteEnabled: true);
graphics.SetBlendState(BlendMethod.Transparency);
// Input layout
graphics.SetLayout("effect.fx", "VS", "vs_4_0",
new InputElement("POSITION", 0, Format.R32G32B32_Float, 0),
new InputElement("TEXCOORD", 0, Format.R32G32_Float, 0)
);
// Vertex shader
graphics.SetShader(Shader.Vertex, "effect.fx", "VS", "vs_4_0");
graphics.SetConstants(Shader.Vertex, 0, 4, stream => stream.Write(wvpMatrix));
// Pixel shader
graphics.SetShader(Shader.Pixel, "effect.fx", "PS", "ps_4_0");
graphics.SetTexture(Shader.Pixel, 0, texture);
graphics.SetSampler(Shader.Pixel, 0, Sampler.AnisotropicWrap);
graphics.SetConstants(Shader.Pixel, 0, 1, stream => stream.Write(new Color4(1, 0, 1, 0);
d3d.Run(() =>
{
// Draw and present
d3d.BackBuffer.Clear(new Color4(1, 0, 0.5f, 1));
graphics.SetOutput(d3d.BackBuffer);
graphics.Draw(mesh);
d3d.Present();
}