グラフィックスを扱うとき、私はしばしば多くの時期尚早な最適化を行う傾向があります。私が常に従おうとするいくつかの原則があります。
- D3Dコンポーネントの数を最小限に抑えます。(レンダリング状態、バッファー、シェーダーなど)
- どうしても必要な場合にのみコンポーネントをバインドします。(まだバインドされていないなど)
- コンポーネントをできる限り専門化します。(必要なBindFlagsのみを設定するなど)
これにより、作成されたコンポーネントと現在のパイプライン状態を管理するための非常に手の込んだラッパーを構築することになりました。これは私の貴重な開発時間の多くを消費するだけでなく、複雑さをさらに大きくします。
そして最悪の事態: 場合、それがすべてトラブルに値するかどうかさえ知りません。
私の最適化の考慮事項のいくつかは、すでに下位レベルで実装されている可能性があり、それらを複製しているだけで、CPUの時間をさらに浪費しています。パフォーマンスへの影響は無視できるため、他の考慮事項は完全に不要な場合があります。
だから私の質問は:
- 上記のガイドラインのうちどれが有効で、どの程度遵守する必要がありますか?
- GPUは状態の変化をどのように処理しますか?
- 使用されていない状態を変更するとどうなりますか?(アクティブな間は、描画呼び出しは行われません。)
- さまざまな異なるコンポーネントをバインドするための実際のパフォーマンスペナルティは何ですか?
- 他にどのようなパフォーマンスの考慮事項を行う必要がありますか?
実際の制限に達するまでは、パフォーマンスについて気にしないでください。それは明らかに実用的な見地からは真実ですが、私は主に理論に興味があります。どういうわけか、最適なグラフィックスフレームワークを構築するという衝動と闘う必要がありますが、通常の「時期尚早の最適化講義」ではそれを実現できないと思います。
コンポーネントの管理
現在、SlimDXをマネージラッパーとして使用して、DirectX 11アプリケーションをC#で作成しています。これは非常に低レベルのラッパーであり、私の現在の抽象化はその上に構築されています。
Direct3D抽象化を使用する場合、いくつかの明らかな利点があります。環境の設定、シェーダーの読み込み、定数の設定、メッシュの描画は、はるかに簡単で、使用するコードが大幅に少なくなります。また、ほとんどのコンポーネントの作成と破棄を管理するため、どこでも自動的に再利用でき、メモリリークをほぼ完全に回避できます。
- 通常、すべてのグラフィックコンポーネントとリソースをどのように管理しますか?
- 以下の私の例と同様のことを行うマネージラッパーを推奨できますか?
これが私の現在の実装例です。インターフェースにとても満足しています。私のニーズに対して十分な柔軟性があり、使用および理解が非常に簡単です。
// 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();
}