CPU - GPU bellek veri akışı [kapalı]


16

Yeni başlayan bir grafik programcısıyım ve son zamanlarda merak ediyorum - model verileri (kafesler ve malzemeler) uygulamadan (CPU belleği) grafik kartına (GPU belleği) nasıl akıyor? Bir kez yükleyip kurduğum ve uygulama ömrü boyunca değişmediğim statik bir modelim (örneğin bir bina) olduğunu varsayalım.

  • Verileri GPU belleğine yalnızca bir kez gönderilip orada sonsuza kadar oturuyor mu?
  • Model aslında her kareyi oluşturduğunda GPU işlemcilerinin verilerini her seferinde GPU belleğinden alması gerekir mi? Demek istediğim - her biri birden çok kez işlenmiş 2 modelim olsaydı - ilkini birden çok kez ve sonra ikincisini birden çok kez oluştursaydım ya da ilkini bir kez oluşturduysam, ikincisini sadece bir kez ve böyle bırakmaya devam ettiniz mi? Bu soruya bu anlamda "dahili GPU veri akışı" diyebilirim.
  • Açıkçası grafik kartlarının sınırlı RAM'i var - 1 kare oluşturmak için gerekli tüm model verilerini tutamadığında, sanırım her bir kareyi CPU RAM'inden (bazıları) getirmeye devam ediyor, doğru mu?

İnternette bununla ilgili çok fazla kitap ve malzeme olduğunu biliyorum, ancak belki de bu veri akışını nasıl yöneteceğinize dair hızlı genel kurallarınız var (ne zaman ve ne kadar, ne zaman ve nasıl oluşturulacağı)?

Düzenleme: olduğunumu: Bir ayrım yapmak unuttum GPU veri gönderen ve orada oluyor şimdiki gibi tamponlar bağlayıcı / ayar . İkincisi herhangi bir veri akışına neden oluyor mu?

Edit2: Raxvan'ın gönderisini okuduktan sonra birkaç işlemi ayırt etmek istiyorum:

  • başlatma ile arabellek oluşturma (dedi ki verileri CPU ram veya GPU'da saklayabilirim)
  • arabellek veri güncellemesi (veri CPU ram'da tutulduğunda basittir ve GPU ram'da tutulduğunda GPU'dan CPU ram'a (ve sonra geri) getirilmesini gerektirir)
  • arabellek etkin olarak bağlama (sadece API bu arabellek sonraki beraberlik çağrısı işlenmesini istiyorum ve kendi başına bir şey yapmaz söylemek için bir yolu var mı?)
  • API çizme çağrısı (burada gerçekte ne olduğunu sizden duymak istiyorum)

Hiçbir şekilde uzman değilim, ancak VAO ve VBO'larla modern (yani hemen değil) OpenGL kullanıyorsanız, veriler GPU'ya gönderilir ve glBuffer komut ailesinden birini kullandığınızda VRAM'da depolanır. Ardından, her çizdiğinizde, ilgili köşeler VRAM'den alınır ve oluşturulur. Hareket eden bir modelse, statik olarak saklama eğilimindedir ve model uzayından dünya / kamera uzayına geçmek için matrisler kullanırsınız. Son noktaya gelince, RAM'iniz bittiğinde ne olacağı hakkında hiçbir fikrim yok. Benim tahminim, eğer VRAM tükenirse, veri muhtemelen bir hata kodu ile gönderilmez.
Polar

@Polar - tam olarak değil. GL aslında bir arabellek nesnesinin hangi bellekte saklandığını belirtmez ve kullanım modeline bağlı olarak çalışma zamanında hareket ettirmekte bile özgürdür. GL4.4 buna biraz değiniyor, ancak sonunda sağlayabileceği en iyi şeyin "o aptalca ipucu şeylerinden biri" olduğuna dikkat çekiyor; bkz. opengl.org/registry/specs/ARB/buffer_storage.txt ve özellikle Sayılar 2 ve 9.
Maximus Minimus

1
@JimmyShelter Ah, teşekkürler - "o aptalca ipucu şeylerinden" daha az ve daha somut bir spesifikasyona sahip olsaydık iyi olurdu.
Polar

@Polar - ne sinir bozucu ARB_buffer_storage olmasıdır olabilir henüz başka ipucu da dahil kaçındık, ama tasarımcılar fırsatı kaçırdı. Oh, belki 4.5 sonunda doğru olacak.
Maximus Minimus

2
Lütfen sorularınızı cevaplara "yanıt vermek" için düzenlemeyin. Bunun yerine yeni bir soru gönderin.

Yanıtlar:


12

Verileri GPU belleğine yalnızca bir kez gönderilip orada sonsuza kadar oturuyor mu?

Genellikle evet, ancak sürücü "optimal" olanı yapmakta özgürdür, veriler VRAM veya RAM'de saklanabilir veya burada önbelleğe alınabilir ve VBO akışında gerçekte ne olduğunu açıklayan bir aksaklıktır .

Örneğin, dinamik bir openGL tamponu (örneğin VBO) olarak işaretlenmişse, RAM'de depolanması daha olasıdır. GPU, ram'a CPU müdahalesi olmadan doğrudan erişmek için doğrudan bellek erişimi (DMA) kullanır; bu, grafik kartı ve grafik sürücüsündeki DMA denetleyicisi tarafından kontrol edilir ve çekirdek modunda yürütülür.

Model aslında her bir kareyi oluşturduğunda, bir model birden fazla ardışık zaman oluştursa bile GPU işlemcilerinin verilerini her seferinde GPU belleğinden alması gerekir mi?

Tıpkı CPU'lar gibi, GPU'ların da GPU talimatlarını ve bellek erişim işlemlerini yeniden sipariş etmesine izin verilir (okuma: bozuk yürütme ), bu nedenle büyük olasılıkla GPU, önbelleğindeki belleğe erişerek (genellikle son zamanlarda erişilen) senaryoyu ele alır ), ancak bazen bunu yapamaz.

Açıkçası grafik kartlarının sınırlı RAM'i var - 1 kare oluşturmak için gerekli tüm model verilerini tutamadığında, sanırım her bir kareyi CPU RAM'inden (bazıları) getirmeye devam ediyor, doğru mu?

Bunun olmasını istemiyorsun. Ancak bu olursa olsun, GPU, RAM ve VRAM (GPU'daki komut işlemcisi bundan sorumludur) arasında belleği hareket ettirmeye başlayacaktır, bu da GPU'nun durmasına neden olacak şekilde işlemeyi çok daha yavaş hale getirecektir, çünkü verileri beklemesi gerekecektir / V / RAM'e kopyalanacaktır.

Verileri GPU'ya gönderiyor ve arabellekleri güncel olarak ayarlıyor / bağlıyor. İkincisi herhangi bir veri akışına neden oluyor mu?

GPU'lar bir komut arabelleği içerir ve tüm API komutları bu arabelleğe gönderilir, bunun GPU'ya kopyalanan verilerle aynı anda olabileceğini unutmayın. Komut halka tampon CPU ve grafik işlemcinin arasında bir iletişim kuyruğudur GPU ile execulated böylece ihtiyaçları sıraya gönderilmesi gereken yürütülecek bu, herhangi bir komut. Tıpkı herhangi bir işlem bağlama gibi, bazı bellek konumlarına erişebilmesi için gpu'ya yeni arabelleklerin gönderilmesi gerekir.

Bu, glBegin / glEnd'in kullanımdan kaldırılmasının nedenlerinden biridir, yeni komutların gönderilmesi için kuyruk senkronizasyonu gerekir (bellek çitleri / bariyerleri kullanarak).

resim açıklamasını buraya girin

Diğer puanlarınız için:

Başlatma ile tampon oluşturma

Bir arabelleği başlatmadan ayırabilir ve daha sonra kullanmak üzere saklayabilirsiniz. Ya da bir arabellek ayırabilir ve aynı anda veri kopyalayabilirsiniz (API düzeyi hakkında konuşmak).

arabellek veri güncellemesi

GPU tarafındaki belleği güncellemek için glMapBuffer kullanabilirsiniz. belleğin RAM'den / RAM'e kopyalanıp kopyalanmayacağı aslında standardın bir parçası değildir ve Satıcı, GPU türü ve sürücüye bağlı olarak büyük ölçüde değişecektir.

API çizme çağrısı (burada gerçekte ne olduğunu sizden duymak istiyorum).

Ana sorudaki ikinci noktam bunu kapsıyor.

tamponu aktif olarak bağlama (API'ye bu tamponun sonraki çizim çağrısında işlenmesini istediğimi söylemenin bir yolu var mı ve tek başına bir şey yapmıyor mu?)

Bağlamayı, thiskesinlikle aynı olmasa da, herhangi bir nesne yönelimli dilde işaretçi kullanmak olarak düşünün .


3

Genel olarak cpu'nun gpu'ya karşı sınırı ve katılımı platforma özgüdür, ancak çoğu bu modeli takip eder: cpu bir miktar ram, gpu da içerir ve hafızayı hareket ettirebilirsiniz (bazı durumlarda ram paylaşılır, ancak basitlik uğruna ayrı koçlara yapışalım).

ilk nokta : İlk başlattığınız verileri CPU ramında veya GPU ramında tutmayı seçebilir ve her ikisi için de avantajları vardır. GPU'nun ağır kaldırma işlemini gerçekleştirmesi gereken bir şey oluşturduğunuzda, GPU belleğinde bulunan verilerin daha iyi performans sağlayacağı açıktır. CPU için önce GPU'ya veri göndermelidir (bu da bir süre saklamayı seçebilir) ve ardından render işlemini gerçekleştirmelidir.

ikinci nokta : Oluşturmada birçok hile vardır, ancak işin asıl yolu çokgenlerdir. Bir çerçeve üzerinde gpu çokgenlerden yapılmış nesneleri teker teker ve GPU'nun resmi ekrana göndereceğini bitirdikten sonra yapar. Nesneler gibi bir kavram yoktur, sadece çokgenler vardır ve onları bir araya getirme şekli bir görüntü yaratacaktır. GPU'nun görevi, bu çokgenleri 3d'den 2d'ye yansıtmak ve efekt uygulamaktır (istenirse). Çokgenler yalnızca doğrudan CPU-> GPU-> SCREEN veya GPU-> SCREEN ile gider (çokgenler zaten GPU ram'daysa)

üçüncü nokta : Örneğin animasyonları oluşturduğunuzda, verileri cpu'ya yakın tutmak daha iyidir, çünkü ağır kaldırma yapıyor, verileri GPU'da tutmak, CPU'ya taşımak ve her kareyi geri taşımak en uygun olmayacaktır. Saymak için bunun gibi birçok örnek var, ancak genel olarak tüm veriler hesaplamaları yapanlara yakın kalacak. Genellikle performans elde etmek için GPU koçuna mümkün olduğunca fazla veri taşımak istersiniz.

Gerçek gönderme gpu veri API yapmak istediğiniz anlayan böylece kullandığınız API (directx / opengl veya başka) ve bunun gibi bağlayıcı ve malzeme kavramı ile sadece soyutlamalar edilir yapılır.

Düzenleme için düzenleme:

  • buffer creation with initialisation: int a = new int[10]ile a[0] = 0,a[1] = 1.... etc arabellek oluşturduğunuzda, veri için yer açarsınız ve verileri başlattığınızda istediğiniz şeyleri oraya koyarsınız.

  • buffer data updatecpu ram üzerindeyse, vertex * verticesonunla oynayabileceğinize sahip olursunuz, eğer orada değilse, GPU'dan taşımanız gerekir vertex * vertices = map(buffer_id);(harita, GPU'dan CPU ram'a veri taşıması gereken mitolojik bir işlevdir, ayrıca optiktir) buffer_id = create_buffer(vertices);

  • binding the buffer as activebu sadece bindingişleme olarak adlandırdıkları karmaşık bir süreçtir ve 10000 parametreli bir işlevi çağırmak gibidir. Bağlama, hangi tamponun nereye gittiğini söylemek için kullandıkları bir terimdir. Bu terimin arkasında gerçek bir sihir yoktur, tamponları dönüştürmez veya taşımaz veya yeniden tahsis etmez, sürücüye bir sonraki çizim çağrısında bu tamponu kullandığını söyler.

  • API draw callTüm ciltleme ve ayar tamponlarından sonra bu, kauçuğun yolla buluştuğu yerdir. Çizim çağrısı, belirttiğiniz tüm verileri (veya verileri işaret eden kimlik bilgilerini) alır, GPU'ya gönderir (gerekirse) ve GPU'ya sayıları ezmeye başlamasını söyler. Bu, tüm platformlarda tam olarak doğru değildir, birçok fark vardır, ancak işleri basit tutmak için çizime GPU'ya ... çizmesini söyleyecektir.


2

En doğru cevap, onu nasıl programladığınıza bağlıdır, ancak bu endişelenmeniz gereken iyi bir şeydir. GPU'lar inanılmaz derecede hızlı olsa da, GPU RAM'e giden ve GPU'dan bant genişliği değil ve en sinir bozucu darboğazınız olacak.

Verileri GPU belleğine yalnızca bir kez gönderilip orada sonsuza kadar oturuyor mu?

Umarım, evet. Oluşturma hızı için, her kareyi yeniden göndermek yerine GPU'da olabildiğince fazla verinin olmasını istersiniz. VBO'lar bu amaca hizmet eder. Hem statik hem de dinamik VBO'lar vardır, birincisi statik modeller için en iyisidir ve ikincisi, köşeleri her kareyi (örneğin bir parçacık sistemi) değiştirecek modeller için en iyisidir. Dinamik VBO'lar söz konusu olduğunda bile, her karede tüm köşeleri yeniden göndermek istemezsiniz; sadece değişenler.

Yapınız söz konusu olduğunda, köşe verileri sadece orada oturur ve değişen tek şey matrislerinizdir (model / dünya, projeksiyon ve görünüm).

Bir parçacık sistemi söz konusu olduğunda, o sistem için var olacak maksimum parçacık sayısını depolayacak kadar büyük bir dinamik VBO yaptım. Her bir kareyi, bu kareyi yayan parçacıkların verilerini, birkaç üniformayla birlikte gönderiyorum ve hepsi bu. Çizdiğimde, o VBO'da bir başlangıç ​​ve bitiş noktası belirtebiliyorum, bu yüzden parçacık verilerini silmek zorunda değilim. Sadece bunları çizme diyebilirim.

Model aslında her kareyi oluşturduğunda GPU işlemcilerinin verilerini her seferinde GPU belleğinden alması gerekir mi? Demek istediğim - her biri birden çok kez işlenmiş 2 modelim olsaydı - ilkini birden çok kez ve sonra ikincisini birden çok kez oluştursaydım ya da ilkini bir kez oluşturduysam, ikincisini sadece bir kez ve böyle bırakmaya devam ettiniz mi?

Sadece bir yerine birden fazla çekiliş çağrısı gönderme işlemi çok daha büyük bir sınırdır. Anlık oluşturmaya göz atın; size çok yardımcı olabilir ve bu sorunun cevabını işe yaramaz hale getirebilir. Bununla ilgili henüz çalışmadığım bazı sürücü sorunlarım vardı, ancak çalıştırabilirseniz, sorun çözüldü.

Açıkçası grafik kartlarının sınırlı RAM'i var - 1 kare oluşturmak için gerekli tüm model verilerini tutamadığında, sanırım her bir kareyi CPU RAM'inden (bazıları) getirmeye devam ediyor, doğru mu?

GPU RAM'iniz bitmek istemezsiniz. Eğer öyleyse, o zaman bir şeyleri değiştirerek değiştirmeyin. Yaptığınız varsayımsal senaryoda, muhtemelen bir şekilde çökecek, ama bunun olduğunu hiç görmedim, bu yüzden dürüstçe bilmiyorum.

Bir ayrım yapmayı unuttum: GPU'ya veri gönderiyor ve arabellekleri güncel olarak ayarlıyor / bağlıyor. İkincisi herhangi bir veri akışına neden oluyor mu?

Önemli bir veri akışı yok, hayır. Bunun bir maliyeti var, ancak bu yazdığınız her kod satırı için geçerlidir. Size maliyetinin ne olduğunu bulmak yine profil oluşturmanın ne için olduğunu.

başlatma ile tampon oluşturma

Raxvan'ın cevabı kulağa hoş geliyor, ama tam olarak doğru değil. OpenGL'de, arabellek oluşturmak herhangi bir yer ayırmaz . Herhangi bir veri iletmeden yer ayırmak istiyorsanız glBufferData öğesini çağırabilir ve null iletebilirsiniz. ( Buradaki notlar bölümüne bakın .)

arabellek veri güncellemesi

Sanırım glBufferData veya bunun gibi diğer işlevler demek değil mi? Gerçek veri aktarımı burada gerçekleşir. (Son paragrafta söylediğim gibi boş kalmazsanız.)

arabellek etkin olarak bağlama (sadece API bu arabellek sonraki beraberlik çağrısı işlenmesini istiyorum ve kendi başına bir şey yapmaz söylemek bir yolu var mı?)

Evet, ama bundan biraz daha fazlasını yapabilir. Örneğin, bir VAO'yu (köşe dizisi nesnesi) bağlarsanız, bir VBO'yu bağlarsanız, o VBO VAO'ya bağlanır. Daha sonra, VAO'yu tekrar bağlar ve glDrawArrays'i çağırırsanız, hangi VBO'nun çizileceğini bilecektir.

Birçok öğretici her VBO için bir VAO oluşturmanıza rağmen, bunun amaçlanan kullanımı olmadığı söylendi. Sözde bir VAO oluşturmalı ve bunu aynı özelliklere sahip her VBO ile kullanmalısınız. Bunu henüz denemedim, bu yüzden daha iyi ya da kötü olup olmadığını kesin olarak söyleyemem.

API çizim çağrısı

Burada olanlar oldukça basittir (bizim açımızdan). Bir VAO bağladığınızı ve ardından glDrawArrays'ı arayın. Bir başlangıç ​​noktası ve bir sayı belirtirsiniz ve o aralıktaki her köşe için köşe gölgelendiricinizi çalıştırır, bu da çıktılarını satırdan geçirir. Bütün bu süreç kendi başına bir başka denemedir.


"o zaman sorun çözüldü" Evet, örnekleme çok yardımcı olacaktır, ancak onsuz her nesne için bir beraberlik çağrısı yapmak zorunda kalacağım. Her iki durumda da aynı şey. Bu yüzden siparişin önemli olup olmadığını merak ediyorum.
NPS

@NPS - Bazı önemli . Eğer sipariş edilirlerse, bağlarınızı değiştirmeye devam etmek zorunda kalmazsınız, evet, muhtemelen küçük bir miktar daha hızlı olacaktır. Ama bunları sıralamak için kendi yolunuzdan çıkmak zorunda kalırsanız, bu muhtemelen çok, çok daha maliyetli olacaktır. Bundan çok daha fazlasını söylemek için uygulamanıza bağımlı çok fazla değişken var.
Icy Defiance
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.