Grafiklerle uğraşırken genellikle çok erken bir optimizasyon yapma eğilimindeyim. Her zaman izlemeye çalıştığım birkaç ilke vardır:
- D3D bileşenlerinin sayısını minimumda tutun. (Durumları, tamponları, gölgelendiricileri vb. İşle)
- Bileşenleri yalnızca kesinlikle gerekliyse bağlayın. (Zaten bağlı değil vb.)
- Bileşenleri mümkün olduğunca uzmanlaştırın. (Yalnızca gerekli BindFlags vb. Ayarlayın)
Bu, beni oluşturulan bileşenleri ve mevcut borulama durumunu yönetmek için çok ayrıntılı sarmalayıcılar oluşturmaya götürdü. Bu sadece değerli gelişim zamanımın çoğunu tüketmekle kalmaz, aynı zamanda başka bir büyük karmaşıklık katmanı ekler.
Ve en kötüsü: Her şeyin belaya değip değmeyeceğini bile bilmiyorum.
Optimizasyonla ilgili düşüncelerimin bazıları zaten daha düşük bir düzeyde uygulanabiliyor ve bunları tekrar ediyorum, ayrıca CPU'da zaman harcıyorum. Performans üzerindeki etkisi önemsiz olduğu için diğer hususlar tamamen gereksiz olabilir.
Yani sorularım:
- Yukarıdaki kılavuzlardan hangisi geçerlidir ve ne ölçüde uymalıyım?
- GPU durum değişikliklerini nasıl gerçekleştirir?
- Hiç kullanılmayan bir durumu değiştirirsem ne olur? (Etkinken hiçbir çizim çağrısı yapılmaz.)
- Çeşitli bileşenleri birleştirmek için gerçek performans cezaları nelerdir?
- Başka hangi performans hususları dikkate alınmalıdır?
Lütfen bana sadece gerçek sınırlara ulaşana kadar performansı önemsememem gerektiğini söylemeyin. Bu pratik açıdan açık olsa da, esasen teoriyle ilgileniyorum. Bir şekilde optimal grafik çerçevesini oluşturma dürtüsü ile mücadele etmem gerekiyor ve bunu "erken optimizasyon dersi" ile yapabileceğimi sanmıyorum.
Bileşenleri yönetme
Şu anda yönetilen sarıcı olarak SlimDX kullanarak C # DirectX 11 uygulamaları yazıyorum. Çok düşük seviyeli bir sargıdır ve mevcut soyutlamam bunun üzerine inşa edilmiştir.
Direct3D soyutlama kullanmanın bazı belirgin avantajları vardır. Ortamı kurmak, gölgelendiricileri yüklemek, sabitleri ayarlamak ve bir kafes çizmek çok daha basittir ve çok daha az kod kullanır . Ayrıca, çoğu bileşenin oluşturulmasını ve atılmasını yönettiği için, otomatik olarak her yerde yeniden kullanılabilirler ve bellek sızıntılarından neredeyse tamamen kaçınırım.
- Tüm grafik bileşenlerini ve kaynaklarını genellikle nasıl yönetirsiniz?
- Aşağıdaki örneğime benzer bir şey yapmayı yöneten herhangi bir sarmalayıcı önerebilir misiniz?
İşte mevcut uygulamamın bir örneği. Arayüzden oldukça memnunum. İhtiyacım için yeterli esnekliğe sahip ve kullanımı ve anlaşılması çok basit:
// 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();
}