If-Koubou

Cum procesează GPU-ul și GPU-ul pentru a desena grafica pe calculator?

Cum procesează GPU-ul și GPU-ul pentru a desena grafica pe calculator? (Cum să)

Unitatea centrală de procesare (CPU) și unitatea de procesare grafică (GPU) a computerului interacționează în fiecare moment în care utilizați computerul pentru a vă oferi o interfață vizuală clară și receptivă. Citiți mai departe pentru a înțelege mai bine cum lucrează împreună.

Fotografie de sskennel.

Sesiunea de întrebări și răspunsuri din ziua de astăzi vine de la amabilitatea programului SuperUser - o subdiviziune a Stack Exchange, o grupare de comunicații pe site-uri cu întrebări și răspunsuri.

Intrebarea

Cititorul super-utilizator Sathya a pus întrebarea:

Aici puteți vedea o captură de ecran a unui mic program C ++ numit Triangle.exe cu un triunghi rotativ bazat pe OpenGL API.

Desigur, un exemplu foarte simplu, dar cred că este aplicabil și altor operațiuni cu carduri grafice.

Am fost curios și am vrut să cunosc întregul proces făcând clic dublu pe Triangle.exe sub Windows XP până când pot vedea triunghiul rotindu-se pe monitor. Ce se întâmplă, cum interacționează CPU (care manipulează mai întâi .exe) și GPU (care trimit în cele din urmă triunghiul pe ecran)?

Cred că implicat în afișarea acestui triunghi rotativ este în primul rând următoarele hardware / software, printre altele:

Hardware

  • HDD
  • Memoria sistemului (RAM)
  • Procesor
  • Memorie video
  • GPU
  • Ecran LCD

Software-ul

  • Sistem de operare
  • DirectX / OpenGL API
  • Nvidia Driver

Poate cineva să explice procesul, poate cu un fel de grafic pentru ilustrare?

Nu ar trebui să fie o explicație complexă care să acopere fiecare pas (presupunem că ar depăși domeniul de aplicare), dar o explicație pe care un tip IT intermediar poate să o urmeze.

Sunt sigur că o mulțime de oameni care chiar s-ar numi profesioniști IT nu au putut descrie acest proces corect.

Răspunsul

Deși mai mulți membri ai comunității au răspuns la întrebare, Oliver Salzburg a mers extra mile și a răspuns nu doar cu un răspuns detaliat, ci și cu o excelentă grafică însoțitoare.

Imagine de JasonC, disponibilă ca tapet aici.

El scrie:

Am decis să scriu un pic despre aspectul de programare și modul în care componentele vorbesc unul cu celălalt. Poate că va lumina anumite zone.

Prezentarea

Ce este nevoie să ai chiar acea singură imagine, pe care ai postat-o ​​în întrebarea ta, desenată pe ecran?

Există mai multe moduri de a desena un triunghi pe ecran. Pentru simplificare, să presupunem că nu s-au folosit tampoane de vertex. (A vertex tamponeste o zonă de memorie unde stocați coordonatele.) Să presupunem că programul a spus pur și simplu conductei de procesare grafică despre fiecare vertex (un vertex este doar o coordonată în spațiu) într-un rând.

Dar, înainte să putem trage ceva, mai întâi trebuie să executăm niște schele. Vom vedea De ce mai tarziu:

// Ștergeți ecranul și bufferul de adâncime glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Resetați Matricea curentă de vizualizare a modelului glMatrixMode (GL_MODELVIEW); glLoadIdentity (); // Desenul folosind glangine triunghiulare (GL_TRIANGLES); // Red glColor3f (1.0f, 0.0f, 0.0f); // Topul triunghiului (Frontul) glVertex3f (0.0f, 1.0f, 0.0f); // verde glColor3f (0.0f, 1.0f, 0.0f); // Stânga triunghiului (Front) glVertex3f (-1.0f, -1.0f, 1.0f); // Blue glColor3f (0.0f, 0.0f, 1.0f); // Dreptul triunghiului (Front) glVertex3f (1.0f, -1.0f, 1.0f); // Efectuat desenul glEND ();

Și ce a făcut asta?

Când scrieți un program care dorește să utilizeze placa grafică, veți alege, de obicei, un tip de interfață pentru driver. Unele interfețe bine cunoscute conducătorului auto sunt:

  • OpenGL
  • Direct3D
  • CUDA

Pentru acest exemplu vom rămâne cu OpenGL. Acum, tu interfață cu șoferul este ceea ce vă oferă toate instrumentele de care aveți nevoie pentru a vă face programul vorbi pe placa grafică (sau pe conducătorul auto, care apoi tratative pe card).

Această interfață este obligată să vă ofere anumite cerințe unelte. Aceste instrumente au forma unui API pe care îl puteți apela din programul dvs.

API-ul este ceea ce vedem utilizându-se în exemplul de mai sus. Să aruncăm o privire mai atentă.

Schele

Înainte de a putea să faci cu adevărat un desen real, va trebui să faci a înființat. Trebuie să definiți portul de vizualizare (zona care va fi efectiv redată), perspectiva dvs. ( aparat foto în lumea ta), ce anti-aliasing vei folosi (pentru a netezi marginea triunghiului tău) ...

Dar nu ne vom uita la asta. Vom arunca o privire asupra lucrurilor pe care trebuie să le faceți fiecare cadru. Ca:

Ștergerea ecranului

Conducta grafică nu va șterge ecranul pentru fiecare cadru. Va trebui să-i spui. De ce? De-aceea:

Dacă nu ștergeți ecranul, pur și simplu trageți fiecare cadru. De aceea sunăm glClear cuGL_COLOR_BUFFER_BIT a stabilit. Celălalt bit (GL_DEPTH_BUFFER_BIT) spune OpenGL pentru a șterge adâncimetampon. Acest tampon este folosit pentru a determina ce pixeli sunt în față (sau în spatele) altor pixeli.

Transformare


Sursă de imagini

Transformarea este partea în care luăm toate coordonatele de intrare (vârfurile triunghiului nostru) și aplicăm matricea noastră ModelView. Aceasta este matricea asta explică cum ne model (vârfurile) sunt rotite, scalate și traduse (mutate).

Apoi, aplicăm matricea noastră de proiecție. Aceasta mișcă toate coordonatele, astfel încât să se confrunte cu camera noastră corect.

Acum transformăm încă o dată, cu matricea Viewport. Facem asta pentru a ne scala model la dimensiunea monitorului nostru. Acum avem un set de vârfuri care sunt gata să fie redate!

Vom reveni la transformare un pic mai târziu.

Desen

Pentru a desena un triunghi, putem spune pur și simplu OpenGL să înceapă un nou lista de triunghiuri sunând glBegin cu GL_TRIANGLES constant.
Există și alte forme pe care le puteți desena. Ca o bandă triunghiulară sau un ventilator triunghiular. Acestea sunt în primul rând optimizări, deoarece necesită o mai mică comunicare între CPU și GPU pentru a trage aceeași cantitate de triunghiuri.

După aceasta, putem furniza o listă de seturi de 3 noduri care ar trebui să alcătuiască fiecare triunghi. Fiecare triunghi foloseste 3 coordonate (asa cum suntem in spatiul 3D). În plus, ofer o a culoare pentru fiecare vârf, prin apelareglColor3f inainte de apel glVertex3f.

Umbra dintre cele trei noduri (cele 3 colțuri ale triunghiului) este calculată de OpenGLautomat. Acesta va interpola culoarea pe toată fața poligonului.

Interacţiune

Acum, când faceți clic pe fereastră. Aplicația trebuie doar să captureze mesajul de fereastră care semnalizează clicul. Apoi puteți executa orice acțiune în programul pe care îl doriți.

Acest lucru devine a mult mai dificilă odată ce doriți să începeți să interacționați cu scena dvs. 3D.

Mai întâi trebuie să știți în mod clar la ce pixel utilizatorul a făcut clic pe fereastră. Apoi, luați-vă perspectivăluați în considerare, puteți calcula direcția unei raze, din punctul de acces al mouse-ului în scenă. Puteți calcula apoi dacă există obiecte în scenă intersecteaza cu acea rază. Acum știi dacă utilizatorul a făcut clic pe un obiect.

Deci, cum faceți să se rotească?

Transformare

Sunt conștient de două tipuri de transformări care sunt în general aplicate:

  • Matricea pe bază de transformare
  • Transformarea pe bază de oase

Diferența este aceea oase afecta singur noduri. Matricele afectează întotdeauna toate vârfurile desenate în același mod. Să ne uităm la un exemplu.

Exemplu

Anterior, ne-am încărcat matrice de identitate înainte de a desena triunghiul nostru. Matricea de identitate este una care oferă pur și simplu nici o transformare deloc. Deci, orice am desena, este afectat doar de perspectiva mea. Deci, triunghiul nu va fi rotit deloc.

Dacă vreau să îl rotesc acum, aș putea să fac eu însumi matematica (pe CPU) și să sun pur și simplu glVertex3f cualte coordonate (care sunt rotite). Sau aș putea lăsa GPU-ul să facă toată munca, sunând glRotatefînainte de desen:

// Rotiți triunghiul pe axa Y glRotatef (suma, 0.0f, 1.0f, 0.0f); 

Cantitate este, desigur, doar o valoare fixă. Dacă dorești anima, va trebui să țineți evidența Cantitateși să crească în fiecare cadru.

Așteaptă, ce sa întâmplat cu toată discuția despre matrice mai devreme?

În acest exemplu simplu, nu trebuie să ne pasă de matrice. Pur și simplu sunăm glRotatef și are grijă de toate acestea pentru noi.

glRotate produce o rotație a unghi grade în jurul vectorului x y z. Matricea curentă (seeglMatrixMode) este înmulțită cu o matrice de rotație cu produsul care înlocuiește matricea curentă, deoarece ifglMultMatrix au fost numiți cu matricea următoare ca argument:

x 2 ⁡ 1 - c + cx ı y ⁡ 1 - c - zxx z ⁡ 1 - c + y s y y x 1 - c + z sy 2 ⁡ 1 - c + c z z ⁡ 1 - c - x s 0 x z z ⁡ 1 - c - y syz ⁡ 1 - c + x sz 2 ⁡ 1 - c + c 0 0 0 0 1

Mulțumesc pentru asta!

Concluzie

Ceea ce devine evident este că există multe discuții la OpenGL. Dar nu spune ne orice. Unde este comunicarea?

Singurul lucru pe care îl are OpenGL în acest exemplu este cand e gata. Fiecare operațiune va dura o anumită perioadă de timp. Unele operațiuni durează incredibil de mult, altele sunt incredibil de rapide.

Trimiterea unui vârf la GPU-ul va fi atât de rapid, nici măcar nu aș ști cum să-l exprim. Trimiterea a mii de noduri de la CPU la unitatea de procesare grafică (GPU), în fiecare cadru, este, cel mai probabil, fără nicio problemă.

Ștergerea ecranului poate dura o milisecundă sau mai rău (rețineți, de obicei, aveți numai 16 milisecunde de timp pentru a desena fiecare cadru), în funcție de cât de mare este fereastra de vizualizare. Pentru ao șterge, OpenGL trebuie să deseneze fiecare pixel în culoarea pe care doriți să o eliminați, care ar putea fi milioane de pixeli.

În afară de asta, putem doar să cerem OpenGL doar despre capacitățile adaptorului nostru grafic (rezoluție maximă, max anti-aliasing, adâncime de culoare, ...).

Dar putem, de asemenea, să umplem o textura cu pixeli, fiecare având o anumită culoare. Fiecare pixel păstrează astfel o valoare și textura este un "fișier" uriaș umplut cu date. Putem încărca acest lucru în placa grafică (prin crearea unui buffer de textură), apoi să încărcăm un shader, să spunem că shaderul folosește textura noastră ca o intrare și să execute niște calcule extrem de grele în "fișierul" nostru.

Putem apoi "render" rezultatul calculului nostru (sub formă de noi culori) într-o nouă textura.

Astfel puteți face GPU-ul să funcționeze în alte moduri. Presupun că CUDA se comportă similar cu acest aspect, dar nu am avut ocazia să lucrez cu el.

Chiar am atins doar puțin subiectul întreg. Programarea grafică 3D este o iad al unei ființe.


Sursă imagine

Aveți ceva de adăugat la explicație? Sunați în comentariile. Doriți să citiți mai multe răspunsuri de la alți utilizatori de tehnologie Stack Exchange? Check out discuția completă aici.