Render, gruplar, grafik kartı, performans vb. Hakkında bilgi + XNA?


12

Başlığın biraz belirsiz olduğunu biliyorum ama gerçekten ne aradığımı tanımlamak zor, ama işte gidiyor.

CPU oluşturma söz konusu olduğunda, performansın tahmin edilmesi ve anlaşılması kolaydır, ancak teknik arka plan bilgisi eksikliğimden dolayı GPU söz konusu olduğunda, clueless. XNA kullanıyorum, bu yüzden teorinin bununla ilgili olması hoş olurdu.

Aslında bilmek istediğim şey, belirli çizim eylemleri yaptığınızda ne zaman ve nerede (CPU / GPU) olur? Parti nedir? Etkilerin, projeksiyonların vb. Veriler grafik kartında kalıyor mu veya her adımda aktarılıyor mu? Bant genişliği hakkında konuştuğunuzda, bir grafik kartı dahili bant genişliği veya CPU'dan GPU'ya giden bir boru hattından mı bahsediyorsunuz?
Not: Aslında çizim sürecinin nasıl gerçekleştiği hakkında bilgi aramıyorum , bu GPU'nun işi, bundan önce gelen tüm ek yük ile ilgileniyorum.

X eylemini gerçekleştirdiğimde neler olduğunu anlamak, mimarilerimi ve uygulamalarımı buna uyarlamak istiyorum.

Daha iyi oyunların nasıl yazıldığına dair daha fazla fikir veren tüm makaleler (muhtemelen kod örnekleri ile), bilgiler, bağlantılar, öğreticiler çok takdir edilmektedir. Teşekkürler :)


2
Bu aslında XNA olmasına rağmen, DirectX etiketini ekledim, çünkü bu temel teknolojidir - daha iyi cevaplar almanıza yardımcı olabilir. Ayrıca size iyi bir başlangıç ​​noktası verebilecek bu cevaba da göz atın.
Andrew Russell

@AndrewRussell Çok teşekkürler :). Aslında bu konu da dahil olmak üzere konuyla ilgili çeşitli makaleler okudum. Ama bilmek istediğim her şeyi kapsamıyor.
Aidiakapi

Yanıtlar:


20

Performansı " sınırlar " açısından düşünmeyi seviyorum . Oldukça karmaşık, birbirine bağlı bir sistemi kavramsallaştırmanın kullanışlı bir yoludur. Bir performans sorununuz olduğunda, "Hangi sınırları vuruyorum?" (Veya: "CPU / GPU bağlı mıyım?")

Birden fazla seviyeye ayırabilirsiniz. En üst düzeyde CPU ve GPU var. CPU'ya bağlı (GPU oturumu boşta CPU bekliyor) veya GPU'ya bağlı (CPU GPU'da bekliyor olabilir) olabilir. İşte konuyla ilgili iyi bir blog yazısı .

Daha fazla parçalayabilirsiniz. Açık CPU tarafında, CPU zaten önbellekte verilere tüm döngüleri kullanıyor olabilir. Veya bellek sınırlı olabilir , CPU boşta kalır ve verilerin ana bellekten gelmesini bekler ( bu nedenle veri düzeninizi optimize edin ). Onu daha da bozabilirsin.

(XNA ile ilgili performansa geniş bir genel bakış yaparken, normalde ucuz olsa da, bir referans türünün ( classdeğil struct) tahsisinin, özellikle Xbox 360'ta çok fazla döngü yakacak olan çöp toplayıcısını tetikleyebileceğine işaret edeceğim. . buraya bakın ) detaylar için.

Açık GPU tarafında, ben sizi işaret ederek dışarı başlayacağız bu mükemmel blog post detaylarını çok. Boru hattında çılgın bir ayrıntı düzeyi istiyorsanız , bu blog yayınları dizisini okuyun . ( İşte daha basit olanı ).

Basitçe söylemek gerekirse, büyük olanlardan bazıları şunlardır: " doldurma sınırı " (backbuffer'a kaç piksel yazabilirsiniz - genellikle ne kadar fazla çekime sahip olabilirsiniz), " gölgelendirici sınırı " ( gölgelendiricilerinizin ne kadar karmaşık olabileceği ve bunlardan ne kadar veri aktarabileceğinizi), " doku getirme / doku bant genişliği sınırı " (ne kadar doku verilerine erişebileceğiniz).

Ve şimdi, CPU ve GPU'nun etkileşime girmesi gereken (çeşitli API'ler ve sürücüler aracılığıyla) büyük olana (gerçekten sorduğunuz şey bu) geliyoruz. Gevşek olarak " parti limiti " ve " bant genişliği " vardır. ( Daha önce bahsettiğim dizinin birinci bölümünün kapsamlı ayrıntılara girdiğini unutmayın .)

Ancak, temel olarak, bir toplu iş ( zaten bildiğiniz gibi ), GraphicsDevice.Draw*işlevlerden birini (veya XNA'nın bir kısmını, SpriteBatchsizin için yapar gibi ) çağırdığınızda gerçekleşir . Şüphesiz daha önce okumuş olduğunuz gibi, her kare için bunlardan birkaç bin * alırsınız . Bu bir CPU sınırıdır - bu nedenle diğer CPU kullanımınızla rekabet eder. Temel olarak sürücü, çizmesini söylediklerinizle ilgili her şeyi paketliyor ve GPU'ya gönderiyor.

Ve sonra GPU'nun bant genişliği var . Buraya ne kadar ham veri aktarabileceğinizdir. Bu, toplu işlerle birlikte gelen tüm durum bilgilerini içerir - oluşturma durumunu ve gölgelendirici sabitlerini / parametrelerini ayarlamaktan (dünya / görünüm / proje matrisleri gibi şeyleri içerir), DrawUser*işlevleri kullanırken köşelere kadar her şey . Aynı zamanda herhangi bir çağrı içerir SetDatave GetDatavb dokular, köşe tamponları, üzerinde

Bu noktada diyebileceğim her şeyin SetData(dokular, tepe noktası ve dizin arabellekleri vb.) Yanı sıra Effects - GPU belleğinde kaldığını söylemeliyim . GPU'ya sürekli olarak gönderilmez. Bu verileri referans alan bir çizim komutu, söz konusu verilere bir işaretçi ile gönderilir.

(Ayrıca: yalnızca ana iş parçacığından çizim komutları gönderebilirsiniz, ancak SetDataherhangi bir iş parçacığında yapabilirsiniz .)

XNA Biraz onun hale devlet sınıfları (şeyler karmaşıklaştırır BlendState, DepthStencilStatevs.). Bu durum veri edilir (her partideki) çizim çağrısının başına gönderdi. % 100 emin değilim, ama tembel olarak gönderildiği izlenimi altındayım (sadece değişen durum gönderir). Her iki durumda da, devlet değişiklikleri bir partinin maliyetine göre serbest olana göre ucuzdur.

Son olarak, söylenecek son şey dahili GPU boru hattıdır . Hala okumaya ihtiyaç duyduğu verilere yazarak ya da hala yazması gereken verileri okuyarak onu temizlemek zorunda bırakmak istemezsiniz. Bir boru hattı yıkaması, işlemlerin bitmesini beklediği anlamına gelir, böylece verilere erişildiğinde her şey tutarlı bir durumda olur.

Dikkat edilmesi gereken iki özel durum şunlardır: GetDataDinamik bir şey çağırmak - özellikle RenderTarget2Dde GPU'nun yazabileceği bir şey. Bu performans için son derece kötü - yapma.

Diğer durum SetDataköşe / dizin arabelleklerini çağırıyor . Bunu sık sık yapmanız gerekiyorsa, DynamicVertexBuffer(ayrıca DynamicIndexBuffer) kullanın . Bunlar GPU'nun sık sık değişeceklerini bilmelerini ve boru hattının yıkamasını önlemek için dahili olarak tamponlama sihirleri yapmasını sağlar.

(Ayrıca, dinamik arabelleklerin DrawUser*yöntemlerden daha hızlı olduğunu unutmayın - ancak gereken maksimum boyutta önceden atanmaları gerekir.)

... Ve XNA performansı hakkında bildiğim her şey :)


Size çok teşekkür ederim! Bu tam olarak aradığım ve umduğum şey :).
Aidiakapi

1
Kare başına birkaç yüz parti aşırı karamsar geliyor. Her zaman duyduğum başparmak kuralı kare başına 2K ila 3K serisidir. Bazı oyunların PC'de 10K'a kadar çıktığı biliniyor, ancak bunun başarılması için büyük özen gerektirdiğini düşünüyorum.
Nathan Reed

Oldukça doğru. "Birkaç yüz" rakamı, "1KHz CPU'nun% 100'ü @ 25k yığın / s" olarak listelenen "yığın toplu yığın" kağıdından gelir. Ancak bu kağıt şimdi on yıllıktır ve sürücüler ve CPU'lar o zamandan beri önemli ölçüde iyileşmiştir. Bunu (ve diğerlerini) "birkaç bin" okuyacak şekilde güncelleyeceğim.
Andrew Russell
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.