CPU ve GPU bilgisayar grafiklerini görüntülemede nasıl etkileşime giriyor?


58

Burada, OpenGL API'sini temel alan dönen bir üçgene sahip Triangle.exe adlı küçük bir C ++ programının ekran görüntüsünü görebilirsiniz.

görüntü tanımını buraya girin

Kuşkusuz çok basit bir örnek ama bunun diğer grafik kartı işlemlerine uygulanabilir olduğunu düşünüyorum.

Sadece merak ettim ve Windows XP altında Triangle.exe üzerine çift tıklayarak monitörde dönen üçgeni görene kadar tüm süreci bilmek istedim. Ne olur, CPU (önce .exe'yi işleyen) ve GPU (sonunda üçgeni ekrana çıkaran) nasıl etkileşime girer?

Sanırım bu dönen üçgeni görüntülemede yer almak, öncelikle diğerleri arasında aşağıdaki donanım / yazılımdır:

Donanım

  • HDD
  • Sistem Belleği (RAM)
  • İşlemci
  • Video belleği
  • GPU
  • LCD ekran

Yazılım

  • İşletim sistemi
  • DirectX / OpenGL API
  • Nvidia Sürücüsü

Birisi süreci açıklayabilir mi, belki örnekleme için bir çeşit akış şeması ile?

Her bir adımı kapsayan karmaşık bir açıklama olmamalıdır (kapsamın ötesine geçeceğini tahmin edin), ancak bir ara BT çalışanının izleyebileceği bir açıklama olmamalıdır.

BT uzmanları bile diyebilecek birçok insanın bu süreci doğru tanımlayamadığından eminim.


İkileminiz, GPU’yu CPU’nun bir uzantısı olarak düşünürseniz bitecekti!
KawaiKx

Yanıtlar:


55

Programlama yönü ve bileşenlerin birbirleriyle nasıl konuştuğu hakkında biraz yazmaya karar verdim. Belki bazı bölgelere ışık tutacaktır.

Sunum

Sorunuzda yayınladığınız tek bir görüntünün ekranda çizilmesi bile ne gerekiyor?

Ekranda üçgen çizmek için birçok yol vardır. Basit olması için, hiçbir köşe arabelleğinin kullanılmadığını varsayalım. (Bir köşe arabelleği , koordinatları sakladığınız bir bellek alanıdır.) Programın grafik işleme hattına her bir köşe (bir köşe sadece uzayda bir koordinattır) hakkında anlattığını varsayalım.

Ancak , herhangi bir şey çizmeden önce, ilk önce bir iskele kullanmalıyız. Neden sonra göreceğiz :

// Clear The Screen And The Depth Buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

// Reset The Current Modelview Matrix
glMatrixMode(GL_MODELVIEW); 
glLoadIdentity();

// Drawing Using Triangles
glBegin(GL_TRIANGLES);

  // Red
  glColor3f(1.0f,0.0f,0.0f);
  // Top Of Triangle (Front)
  glVertex3f( 0.0f, 1.0f, 0.0f);

  // Green
  glColor3f(0.0f,1.0f,0.0f);
  // Left Of Triangle (Front)
  glVertex3f(-1.0f,-1.0f, 1.0f);

  // Blue
  glColor3f(0.0f,0.0f,1.0f);
  // Right Of Triangle (Front)
  glVertex3f( 1.0f,-1.0f, 1.0f);

// Done Drawing
glEnd();

Peki bu ne yaptı?

Grafik kartını kullanmak isteyen bir program yazdığınızda, genellikle sürücüye bir çeşit arayüz seçersiniz. Sürücünün iyi bilinen bazı arayüzleri:

  • OpenGL
  • Direct3D
  • CUDA

Bu örnek için OpenGL'ye bağlı kalacağız. Şimdi, sürücüye olan arayüzünüz , programınızın grafik kartıyla (veya daha sonra kartla konuşan sürücüyle) konuşmasını sağlamak için ihtiyaç duyduğunuz tüm araçları sağlayan şeydir .

Bu arayüz size belirli araçlar verecek şekildedir . Bu araçlar programınızdan çağırabileceğiniz bir API şeklini alır .

Bu API, yukarıdaki örnekte kullanıldığını görüyoruz. Hadi daha yakından bakalım.

İskele

Gerçek bir çizim yapmadan önce, bir kurulum yapmanız gerekecektir . Görüntü alanınızı (gerçekte oluşturulacak alan), bakış açınızı ( dünyanızdaki kamera ), kullanacağınız kenar yumuşatma özelliğini (çgenizin kenarını düzeltmek için) tanımlamanız gerekir ...

Ama hiçbirine bakmayacağız. Her karede yapmanız gerekenlere bir göz atacağız . Sevmek:

Ekranı temizlemek

Grafik hattı sizin için her karede ekranı temizlemeyecek. Bunu söylemen gerekecek. Neden? Bu nedenle:

görüntü tanımını buraya girin

Ekranı temizlemezseniz, sadece her karenin üzerine çizersiniz. Dediğimiz bu yüzden glClearbirlikte GL_COLOR_BUFFER_BITsette. Diğer bit ( GL_DEPTH_BUFFER_BIT), OpenGL'ye derinlik tamponunu temizlemesini söyler . Bu tampon, hangi piksellerin diğer piksellerin önünde (veya arkasında) olduğunu belirlemek için kullanılır.

dönüşüm

görüntü tanımını buraya girin
Görüntü kaynağı

Dönüşüm, tüm girdi koordinatlarını (üçgenimizin köşeleri) aldığımız ve ModelView matrisimizi uyguladığımız kısımdır. Bu matristir açıklar bizim nasıl modeli (köşe), döndürülmüş ölçekli ve (taşınır) çevrilir.

Ardından, Projection matrisimizi uyguladık. Bu, tüm koordinatları hareket ettirerek kameralarımıza doğru bakmalarını sağlar.

Şimdi, Viewport matrisimizle bir kez daha dönüşüyoruz. Bunu, modelimizi monitörümüzün boyutuna ölçeklendirmek için yapıyoruz . Şimdi işlenmeye hazır bir dizi köşemiz var!

Biraz sonra dönüşüme döneceğiz.

Çizim

Bir üçgen çizmek için, OpenGL'ye sabit ile çağırarak yeni bir üçgenler listesi başlatmasını söyleyebiliriz . Çizebileceğiniz başka formlar da var. Bir gibi üçgen şerit veya üçgen fan . Bunlar, CPU ve GPU arasında aynı miktarda üçgen çizebilmek için daha az iletişime ihtiyaç duydukları için öncelikli olarak optimizasyonlardır.glBeginGL_TRIANGLES

Bundan sonra, her üçgeni oluşturması gereken 3 köşe kümesinin bir listesini sağlayabiliriz. Her üçgen 3 koordinat kullanır (3B alanda olduğumuz gibi). Ek olarak, çağırmadan önce arayarak her köşe için bir renk de veriyorum .glColor3f glVertex3f

3 köşe (üçgenin 3 köşesi) arasındaki gölge OpenGL tarafından otomatik olarak hesaplanır . Çokgenin tüm yüzündeki rengi enterpolasyon yapar.

etkileşim

Şimdi, pencereye tıkladığınızda. Uygulamanın yalnızca tıklamayı gösteren pencere mesajını yakalaması gerekir . Ardından, programınızda istediğiniz herhangi bir işlemi gerçekleştirebilirsiniz.

3D sahnenizle etkileşime geçmek istediğinizde bu çok daha zorlaşıyor.

Öncelikle, kullanıcının pencereyi hangi pikselde tıklattığını net bir şekilde bilmek zorundasınız. Ardından, bakış açınızı dikkate alarak , farenin tıklaması noktasından sahnenize kadar bir ışın yönünü hesaplayabilirsiniz. Ardından, sahnedeki herhangi bir nesnenin o ışınla kesiştiğini hesaplayabilirsiniz . Artık kullanıcının bir nesneyi tıklayıp tıklamadığını biliyorsunuz.

Peki onu nasıl döndürürsün?

dönüşüm

Genelde uygulanan iki dönüşüm türünün farkındayım:

  • Matris tabanlı dönüşüm
  • Kemik bazlı dönüşüm

Aradaki fark, kemiklerin tek köşeleri etkilemesidir . Matrisler her zaman tüm çizilmiş köşeleri aynı şekilde etkiler. Bir örneğe bakalım.

Örnek

Daha önce, üçgeni çizmeden önce kimlik matrisimizi yükledik . Kimlik matrisi hiçbir şekilde dönüşüm sağlamayandır . Yani, ne çizersem çizeyim sadece bakış açımdan etkilenir. Böylece, üçgen hiç döndürülmeyecek.

Şimdi döndürmek istiyorsanız, ben (CPU üzerine) matematik kendim yapmak ve basitçe diyebiliriz ya glVertex3file diğer (döndürülür) koordinatlarında. Veya glRotatefçizmeden önce arayarak GPU'nun tüm işi yapmasına izin verebilirim :

// Rotate The Triangle On The Y axis
glRotatef(amount,0.0f,1.0f,0.0f);               

amountTabii ki, sadece sabit bir değerdir. Canlandırmak istiyorsanız , amounther kareyi izlemeniz ve arttırmanız gerekir.

Peki, bekle, daha önce tüm matris konuşmalarına ne oldu?

Bu basit örnekte, matrislerle ilgilenmek zorunda değiliz. Biz sadece ararız glRotatefve bizim için herşeyi halleder.

glRotateanglexyz vektörü etrafında derece dönüşü üretir . Geçerli matris (bkz. GlMatrixMode ), mevcut matrisi değiştiren ürünle birlikte bir döndürme matrisi ile çarpılır, sanki glMultMatrix , argümanı olarak aşağıdaki matris ile çağrıldı:

x 2 ⁡ 1 - c + cx ⁢ y ⁡ 1 - c - z ⁢ sx ⁢ z ⁡ 1 - c + y ⁢ s 0 y ⁢ x ⁡ 1 - c + z ⁢ sy 2 ⁡ 1 - c + cy ⁢ z ⁡ 1 - c - x ⁢ s 0 x ⁢ z ⁡ 1 - c - y ⁢ sy ⁢ z ⁡ 1 - c + x ⁢ sz 2 ⁡ 1 - c + c 0 0 0 0 1

Bunun için teşekkürler!

Sonuç

Ne belirginleşmektedir konuşma çok yok demek için OpenGL. Ama bize bir şey anlatmıyor. İletişim nerede

OpenGL’in bize bu örnekte söylediği tek şey, bittiği zaman . Her işlem belirli bir zaman alacaktır. Bazı operasyonlar inanılmaz derecede uzun sürüyor, bazıları ise inanılmaz derecede hızlı.

GPU’ya bir köşe göndermek çok hızlı olacak, nasıl ifade edeceğimi bile bilemedim. İşlemciden GPU'ya binlerce köşe gönderme, her bir kare, büyük olasılıkla, hiç sorun değil.

Ekranı temizlemek, görünüm alanınızın büyüklüğüne bağlı olarak, her kareyi çizmek için genellikle yalnızca yaklaşık 16 milisaniyeniz vardır, aklınızda bulundurun. Bunu temizlemek için, OpenGL'nin temizlemek istediğiniz renkteki her bir pikseli çizmesi gerekir; bu da milyonlarca piksel olabilir.

Bunun dışında OpenGL’ye grafik adaptörümüzün yeteneklerini (maksimum çözünürlük, maksimum kenar yumuşatma, maksimum renk derinliği,…) hakkında sorabiliriz.

Ancak bir dokuyu, her biri belirli bir renge sahip piksellerle doldurabiliriz. Böylece her piksel bir değer tutar ve doku, verilerle dolu dev bir "dosyadır". Bunu grafik kartına yükleyebiliriz (bir doku tamponu oluşturarak), sonra bir gölgelendirici yükleyebilir , bu gölgelendiriciye dokumamızı bir girdi olarak kullanmasını ve "dosyamızda" çok ağır hesaplamalar yapmalarını söyleriz.

Daha sonra, hesaplamanın sonucunu (yeni renkler biçiminde) yeni bir dokuya dönüştürebiliriz.

GPU'nun sizin için başka şekillerde çalışmasını sağlayabilirsiniz. CUDA'nın bu yönüyle benzer performans sergilediğini varsayıyorum, ancak bununla çalışma fırsatım olmadı.

Tüm konuya gerçekten sadece hafifçe dokunduk. 3D grafik programlama bir canavarı cehennem.

görüntü tanımını buraya girin
Görüntü Kaynağı


38

Tam olarak ne anlamadığınızı anlamak zor.

GPU'da, BIOS'un haritaladığı bir dizi kayıt vardır. Bunlar, CPU’nun GPU’nun belleğine erişmesini ve GPU’ya işlem yapma talimatını vermesini sağlar. CPU, GPU'nun belleğinin bir kısmını eşlemek için CPU'yu erişebilmesi için değerleri bu kayıtlara bağlar. Sonra talimatları o hafızaya yükler. Daha sonra GPU’ya, CPU’nun belleğine yüklediği talimatları yerine getirmesini söyleyen bir kayıt yazar.

Bilgi, GPU’nun çalışması için gereken yazılımdan oluşur. Bu yazılım sürücüyle birlikte gelir ve daha sonra sürücü CPU ve GPU arasındaki sorumluluk payını ele alır (kodunun her iki cihazında da kodlarını çalıştırarak).

Ardından sürücü CPU'nun okuyabileceği ve yazabileceği GPU belleğine bir dizi "pencere" yönetir. Genel olarak erişim modeli, CPU'ya talimat veya bilgileri haritalanmış GPU hafızasına yazmayı ve ardından GPU'ya bir sicilden bu talimatı yürütmesi veya bu bilgiyi işlemesi için yönlendirmesini içerir. Bilgi, gölgelendirici mantığı, dokular vb. İçerir.


1
Açıklaman için teşekkürler. Temelde anlamadığım şey CPU talimat setinin GPU talimat setiyle nasıl iletişim kurduğudur, ama belli ki o kısmı yapan sürücü. Soyutlama katmanları ile demek istediğim de buydu.
JohnnyFromBF

2
İlgili CPU talimatı seti yoktur. Sürücü ve çalışma zamanı, CUDA, OpenGL, Direct3D vb. Cihazlarınızı daha sonra da cihaz belleğine yüklenen yerel GPU programlarına / çekirdeklerine derler. Komut tamponu daha sonra başka herhangi bir kaynak gibi olanları ifade eder.
Axel Gneiting

2
Hangi programları kastettiğinizden emin değilim (gpu’da çalıştırılır ve sürücülerle birlikte verilir). Gpu, büyük ölçüde sabit işlevli bir donanımdır ve çalışacağı tek program, sürücü tarafından değil, uygulama tarafından sağlanan gölgelendiricilerdir. Sürücü yalnızca bu programları derler ve sonra bunları GPU hafızasına yükler.
Ben Richards,

1
@ sidran32: Örneğin, nVidia'nın Kepler mimarisinde, çekirdekler, akışlar ve olaylar CPU'da (genellikle) değil, GPU'da çalışan yazılım tarafından oluşturulur. GPU tarafı yazılımı RDMA'yı da yönetir. Bu yazılımların tümü sürücü tarafından GPU belleğine yüklenir ve CPU / GPU işbirliği çiftinin GPU tarafını kullanan GPU'da "mini-OS" olarak çalışır.
David Schwartz

@DavidSchwartz GPU hesaplama görevlerini unuttum. Bununla birlikte, uygulamada yine de gölgelendiricilere benzer davranırlar. Buna rağmen "mini işletim sistemi" demezdim, çünkü işletim sistemlerinde tipik olarak aynı fonksiyonlara sahip değil. Hala çok özel bir yazılım çünkü GPU bir CPU gibi tasarlanmadı (iyi sebeplerden dolayı).
Ben Richards,

13

Sadece merak ettim ve Windows XP altında Triangle.exe üzerine çift tıklayarak monitörde dönen üçgeni görene kadar tüm süreci bilmek istedim. Ne olur, CPU (önce .exe'yi işleyen) ve GPU (sonunda üçgeni ekrana çıkaran) nasıl etkileşime girer?

Bir çalıştırılabilir dosyanın bir işletim sisteminde nasıl çalıştığını ve bu çalıştırıcının GPU'nuzdan monitöre nasıl gönderildiğini bildiğinizi varsayalım, ancak bunlar arasında neler olup bittiğini bilmiyoruz. Öyleyse, donanım yönünden bir göz atalım ve programcı yön yanıtını daha da genişletelim ...

CPU ve GPU arasındaki arayüz nedir?

Bir sürücü kullanarak , CPU, PCI gibi anakart özellikleri üzerinden grafik kartına konuşabilir ve bazı GPU talimatlarını yerine getirmek , GPU hafızasına erişmek / güncellemek, GPU'da çalıştırılacak bir kod yüklemek ve daha fazlası için komutlar gönderebilir ...

Ancak, koddan doğrudan donanım veya sürücüyle konuşamazsınız; bu yüzden OpenGL, Direct3D, CUDA, HLSL, Cg gibi API'ler aracılığıyla gerçekleşmesi gerekecek. Eski çalışma GPU komutlarını çalıştırırken ve / veya GPU hafızasını güncellerken, sonuncusu GPU'da fizik / gölgelendirici dilleri olduğu için kod yürütecektir.

Neden CPU’da değil GPU’da kod çalıştırılsın?

İşlemci günlük iş istasyonumuzu ve sunucu programlarımızı çalıştırmakta iyi olsa da, bugünün oyunlarında gördüğünüz parlak grafikler hakkında pek bir şey düşünülmedi. Günümüzde bazı 2D ve 3D şeylerden hile yapan yazılım üreticileri vardı, ama çok kısıtlayıcılardı. İşte GPU'nun devreye girdiği yer burası.

GPU, grafikteki en önemli hesaplamalardan biri olan Matrix Manipulation için optimize edilmiştir . İşlemci her çarpmayı bir matris manipülasyonunda birer birer hesaplamak zorunda kalsa da (daha sonra 3DNow! Ve SSE gibi şeyler yakalandı), GPU tüm bu çarpımları bir kerede yapabilir! Paralellik.

Ancak paralel hesaplamalar tek sebep değil, başka bir sebep de GPU'nun video belleğine çok daha yakın olması ve bu da işlemciyi CPU, vb.

Bu GPU talimatları / bellek / kod grafikleri nasıl gösterir?

Bunların hepsini çalıştıracak eksik bir parça var, sonra okuyabildiğimiz ve ekrana gönderebileceğimiz bir şeye ihtiyacımız var. Bunu bir framebuffer oluşturarak yapabiliriz . Hangi işlemi yaparsanız yapın, sonunda çerçevedeki pikselleri güncelleyeceksiniz; konumun yanı sıra renk ve derinlik hakkında da bilgi sahibidir.

Size bir yere kan sprite (görüntü) çekmek istediğiniz bir örnek verelim; ilk olarak, ağaç dokusunun kendisi GPU belleğine yüklenir ve bu da istendiğinde yeniden çizilmesini kolaylaştırır. Sonra, sprite'ı aslında bir yere çekmek için sprite'ı tepe noktalarını kullanarak (doğru konuma koyarak), rasterleştirerek (bir 3D nesnesinden piksellere çevirerek) ve çerçeveyi güncelleyerek çevirebiliriz. Daha iyi bir fikir edinmek için, Wikipedia'dan bir OpenGL boru hattı akış şeması aşağıdadır:

Bu, tüm grafik fikrinin ana özüdür, daha fazla araştırma okuyucu için ödevdir.


7

Her şeyi basit tutmak için bunu şöyle tarif edebiliriz. Bazı bellek adresleri (BIOS ve / veya işletim sistemi tarafından) RAM için değil, video kartı için ayrılmıştır. Bu değerlerde (işaretçiler) yazılmış tüm veriler karta gider. Dolayısıyla teoride herhangi bir program sadece adres aralığını bilerek doğrudan ekran kartına yazabilir ve bu tam olarak eski günlerde nasıl yapıldığını ifade eder. Modern işletim sistemlerinde pratikte bu video sürücüsü ve / veya en üstte bulunan grafik kütüphanesi (DirectX, OpenGL vb.) Tarafından yönetilir.


1
-1 CPU'dan bir DirectX API çağrısının GPU ile nasıl iletişim kurabildiğini ve cevabınızın "sürücü ve / veya DirectX tarafından yönetiliyor" olduğunu mu soruyor ? Bu, özel kodun (ala CUDA) nasıl çalıştırılabileceğini de açıklamaz.
BlueRaja - Danny Pflughoeft

3
lütfen okumayı öğren. RAM yerine GPU'ya ayrılan belirli bellek adreslerine yazarak söyledim. Bu da her şeyi nasıl yönetebileceğinizi açıklıyor. Bir kart için bir hafıza aralığı kaydedilir. Bu aralıkta yazdığınız her şey, köşe işleme yapan GPU'ya gider, CUDA, her neyse.
AZ.

5

GPU'lar genellikle DMA arabellekleri tarafından çalıştırılır. Şöyle ki, sürücü kullanıcı alan programından aldığı komutları daha sonra cihaz hafızasına kopyalanan bir talimatlar akışına (anahtar durumu, bu şekilde çiz, anahtar bağlamları vb.) Derler. Daha sonra GPU'ya bu komut arabelleğini bir PCI kaydı ya da benzer yöntemlerle yürütmesini söyler.

Böylece her beraberlik çağrısında vs. olan şey, kullanıcı alanı sürücüsünün komutu derleyeceği, bu durumda çekirdek boşluk sürücüsünü bir kesme yoluyla çağırır ve son olarak komut arabelleğini aygıt belleğine gönderir ve GPU'yu görüntülemeye başlaması için yönlendirir.

Konsollarda, özellikle PS3'te, hepsini kendiniz yapmaktan zevk alabilirsiniz.


0

CPU'nun veriyi GPU'ya veri yolu üzerinden gönderdiğini ve ardından GPU'nun görüntülediğini düşünüyorum. Böylece daha hızlı GPU, CPU'dan daha fazla veri alabilir. Bu şekilde cpuoffload işlemlerinin bir kısmı GPU'ya işlendi. Bu nedenle oyunlarda daha hızlı hız alırsınız.

İşlemcinin depoladığı RAM gibi, böylece hızlı bir şekilde yüklenip işlenebilir. Her ikisi de oyunları daha hızlı yapar.

Veya ses kartı veya net kart aynı prensipte çalışır, bu veriyi almak ve bazı CPU işlerini boşaltmaktır.


Bu, başka bir yanıtı çoğaltır ve yeni bir içerik eklemez. Gerçekten katkıda bulunacak yeni bir şeyiniz yoksa lütfen cevap yazmayın.
DavidPostill

0

Bence op tam olarak ne cpu ekran kartı yapmak için ne söylediğinden ve grafik ile ilgili komutlar (opengl veya direct3d komutları gibi) doğrudan GPU'ya gönderilmediğinden emin değil.

CPU GPU'ya ne yapması gerektiğini söyler. Tüm talimatlar ilk önce işlemcinin üzerinden geçerek işlemcinin GPU'nun gerçeklemesini gerçekleştirmesi için başlatılır / başlatılır.

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.