Hoe werken de CPU en de GPU samen om computerafbeeldingen te maken?
De Central Processing Unit (CPU) en grafische verwerkingseenheid (GPU) van uw computer werken samen op elk moment dat u uw computer gebruikt om u een heldere en responsieve visuele interface te bieden. Lees verder om beter te begrijpen hoe ze samenwerken.
foto door sskennel.
De Question & Answer-sessie van vandaag komt tot ons dankzij SuperUser - een onderdeel van Stack Exchange, een community-drive groep van Q & A-websites.
De vraag
SuperUser-lezer Sathya stelde de vraag:
Hier ziet u een screenshot van een klein C ++ -programma genaamd Triangle.exe met een roterende driehoek op basis van de OpenGL API.
Weliswaar een heel eenvoudig voorbeeld, maar ik denk dat het van toepassing is op andere bewerkingen van grafische kaarten.
Ik was gewoon nieuwsgierig en wilde het hele proces kennen door te dubbelklikken op Triangle.exe onder Windows XP totdat ik de driehoek op de monitor zag draaien. Wat gebeurt er, hoe werken CPU (die eerst de .exe behandelt) en GPU (die uiteindelijk de driehoek op het scherm uitvoeren) met elkaar?
Ik denk dat betrokken bij het weergeven van deze roterende driehoek in de eerste plaats de volgende hardware / software is:
Hardware
- HDD
- Systeemgeheugen (RAM)
- processor
- Video geheugen
- GPU
- LCD scherm
Software
- Besturingssysteem
- DirectX / OpenGL API
- Nvidia Driver
Kan iemand het proces uitleggen, misschien met een soort stroomdiagram ter illustratie?
Het zou geen ingewikkelde uitleg moeten zijn die elke stap omvat (raad die buiten het bereik zou vallen), maar een uitleg die een gemiddelde IT-man kan volgen.
Ik ben er vrij zeker van dat veel mensen die zichzelf zelfs IT-professionals zouden noemen dit proces niet correct kunnen beschrijven.
Het antwoord
Hoewel meerdere communityleden de vraag beantwoordden, deed Oliver Salzburg een extra stap en beantwoordde het niet alleen met een gedetailleerde reactie, maar ook met uitstekende bijbehorende afbeeldingen.
Afbeelding door JasonC, hier beschikbaar als achtergrond.
Hij schrijft:
Ik besloot om een beetje te schrijven over het programmeeraspect en hoe componenten met elkaar praten. Misschien zal het op bepaalde gebieden enig licht werpen.
De presentatie
Wat is er nodig om zelfs die ene afbeelding te hebben die u in uw vraag hebt gepost, getekend op het scherm?
Er zijn veel manieren om een driehoek op het scherm te tekenen. Laten we voor de eenvoud aannemen dat vertexbuffers niet zijn gebruikt. (EEN vertex bufferis een geheugengebied waar je coördinaten opslaat.) Laten we aannemen dat het programma de grafische verwerkingspijplijn eenvoudig vertelde over elke enkele hoekpunt (een hoekpunt is slechts een coördinaat in de ruimte) op een rij.
Maar, Voordat we iets kunnen tekenen, moeten we eerst wat steigers draaien. We zullen zien waarom later:
// Wis het scherm en de dieptebuffer glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Reset de huidige modelzichtmatrix glMatrixMode (GL_MODELVIEW); glLoadIdentity (); // Tekenen met driehoeken glBegin (GL_TRIANGLES); // Rode glColor3f (1.0f, 0.0f, 0.0f); // Top Of Triangle (Front) glVertex3f (0.0f, 1.0f, 0.0f); // Groene 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); // Rechts van driehoek (voorkant) glVertex3f (1.0f, -1.0f, 1.0f); // Klaar met tekenen glEnd ();
Dus wat deed dat?
Wanneer u een programma schrijft dat de grafische kaart wil gebruiken, kiest u meestal een soort interface voor de driver. Enkele bekende interfaces met de bestuurder zijn:
- OpenGL
- Direct3D
- CUDA
Voor dit voorbeeld blijven we bij OpenGL. Nu jij interface naar de bestuurder is wat je alle tools geeft die je nodig hebt om je programma te maken praten naar de grafische kaart (of de driver, die dan gesprekken naar de kaart).
Deze interface zal je zeker zijn hulpmiddelen. Deze tools hebben de vorm van een API die u vanuit uw programma kunt bellen.
Die API is wat we in het bovenstaande voorbeeld gebruiken. Laten we dat van dichterbij bekijken.
De steiger
Voordat u echt een tekening kunt maken, moet u een opstelling. U moet uw viewport definiëren (het gebied dat daadwerkelijk wordt weergegeven), uw perspectief (de camera in je wereld), welke anti-aliasing je zult gebruiken (om de randen van je driehoek glad te strijken) ...
Maar daar zullen we niet naar kijken. We nemen een kijkje in de dingen die je moet doen elk frame. Net zoals:
Het scherm leegmaken
De grafische pipeline zal niet voor elk frame het scherm leegmaken. Je moet het vertellen. Waarom? Dit is waarom:
Als je het scherm niet opruimt, doe je het gewoon teken over het elk frame. Dat is waarom we bellen glClear
met deGL_COLOR_BUFFER_BIT
te stellen. Het andere bit (GL_DEPTH_BUFFER_BIT
) vertelt OpenGL om de te wissen dieptebuffer. Deze buffer wordt gebruikt om te bepalen welke pixels vooraan (of achter) andere pixels zijn.
transformatie
Afbeeldingsbron
Transformatie is het gedeelte waar we alle invoercoördinaten (de hoekpunten van onze driehoek) nemen en onze Matrix ModelView toepassen. Dit is de matrix die legt uit hoe onze model- (de hoekpunten) worden geroteerd, geschaald en vertaald (verplaatst).
Vervolgens passen we onze projectiematrix toe. Hiermee worden alle coördinaten verplaatst zodat ze onze camera correct aankunnen.
Nu transformeren we nog een keer, met onze Viewport-matrix. We doen dit om onze schaal te vergroten model- tot de grootte van onze monitor. Nu hebben we een aantal hoekpunten die kunnen worden weergegeven!
We komen later terug bij de transformatie.
Tekening
Om een driehoek te tekenen, kunnen we OpenGL gewoon vertellen om een nieuwe te starten lijst met driehoeken door te bellen glBegin
met de GL_TRIANGLES
constante.
Er zijn ook andere vormen die u kunt tekenen. Als een driehoekstrook of als driehoeksventilator. Dit zijn voornamelijk optimalisaties, omdat ze minder communicatie vereisen tussen de CPU en de GPU om hetzelfde aantal driehoeken te maken.
Daarna kunnen we een lijst met sets van 3 hoekpunten maken die elke driehoek moeten vormen. Elke driehoek gebruikt 3 coördinaten (zoals we in 3D-ruimte zijn). Daarnaast bied ik ook een kleur voor elke vertex, door te bellenglColor3f
voor roeping glVertex3f
.
De schaduw tussen de 3 hoekpunten (de 3 hoeken van de driehoek) wordt berekend door OpenGLautomatisch. Het interpoleert de kleur over het hele vlak van de veelhoek.
wisselwerking
Nu, wanneer u op het venster klikt. De toepassing hoeft alleen het vensterbericht vast te leggen dat de klik aangeeft. Vervolgens kunt u elke gewenste actie in uw programma uitvoeren.
Dit krijgt een lot moeilijker als je de interactie met je 3D-scène wilt aangaan.
U moet eerst duidelijk weten op welk pixel de gebruiker op het venster klikte. Vervolgens neemt u uw perspectiefrekening houdend met, kunt u de richting van een straal berekenen, vanaf het punt van de muisklik in uw scène. U kunt vervolgens berekenen of een object in uw scène voorkomt snijdt met die straal. Nu weet je of de gebruiker op een object heeft geklikt.
Dus, hoe laat je het draaien?
transformatie
Ik ben me bewust van twee soorten transformaties die over het algemeen worden toegepast:
- Matrix-gebaseerde transformatie
- Bot-gebaseerde transformatie
Het verschil is dat beenderen invloed single hoekpunten. Matrices beïnvloeden altijd alle getrokken hoekpunten op dezelfde manier. Laten we een voorbeeld bekijken.
Voorbeeld
Eerder hebben we onze identiteitsmatrix voor het tekenen van onze driehoek. De identiteitsmatrix is er een die eenvoudig voorziet geen transformatie helemaal niet. Dus, wat ik ook teken, wordt alleen beïnvloed door mijn perspectief. Dus de driehoek zal helemaal niet worden gedraaid.
Als ik het nu wil draaien, kan ik de wiskunde zelf (op de CPU) doen en gewoon bellen glVertex3f
metanders coördinaten (die worden geroteerd). Of ik zou de GPU al het werk kunnen laten doen door te bellen glRotatef
voor het tekenen:
// Roteer de driehoek op de Y-as glRotatef (aantal, 0,0f, 1,0 f, 0,0 f);
bedrag
is, natuurlijk, slechts een vaste waarde. Als je wilt bezielen, je moet het bijhouden bedrag
en verhoog het elk frame.
Dus, wacht, wat is er eerder met de matrixpraat gebeurd?
In dit eenvoudige voorbeeld hoeven we ons geen zorgen te maken over matrices. We bellen gewoon glRotatef
en het zorgt voor dat alles voor ons.
glRotate
produceert een rotatie vanhoek
graden rond de vector x y z. De huidige matrix (seeglMatrixMode) wordt vermenigvuldigd met een rotatiematrix waarbij het product de huidige matrix vervangt, alsof glMultMatrix is aangeroepen met de volgende matrix als argument: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
Nou, bedankt daarvoor!
Conclusie
Wat duidelijk wordt, is dat er veel gepraat wordt naar OpenGL. Maar het is niet vertellen ons iets. Waar is de communicatie?
Het enige dat OpenGL ons in dit voorbeeld vertelt, is wanneer het klaar is. Elke operatie zal een bepaalde hoeveelheid tijd in beslag nemen. Sommige bewerkingen duren ongelooflijk lang, andere zijn ongelooflijk snel.
Een vertex verzenden naar de GPU zal zo snel zijn, ik zou niet eens weten hoe ik het moet uitdrukken. Het verzenden van duizenden hoekpunten van de CPU naar de GPU, elk frame, is waarschijnlijk helemaal geen probleem.
Het scherm leegmaken kan een milliseconde of slechter duren (onthoud dat je meestal maar 16 milliseconden tijd hebt om elk frame te tekenen), afhankelijk van hoe groot je kijkvenster is. Om het te wissen, moet OpenGL elke afzonderlijke pixel tekenen in de kleur die u wilt wissen, dat kunnen miljoenen pixels zijn.
Verder kunnen we OpenGL vrijwel alleen vragen stellen over de mogelijkheden van onze grafische adapter (maximale resolutie, maximale anti-aliasing, maximale kleurdiepte, ...).
Maar we kunnen ook een textuur vullen met pixels die elk een specifieke kleur hebben. Elke pixel heeft dus een waarde en de textuur is een gigantisch "bestand" gevuld met gegevens. We kunnen dat in de grafische kaart laden (door een texture-buffer te maken), dan een shader laden, die shader vertellen om onze textuur als invoer te gebruiken en een aantal extreem zware berekeningen uitvoeren op ons "bestand".
We kunnen het resultaat van onze berekening (in de vorm van nieuwe kleuren) vervolgens "renderen" in een nieuwe textuur.
Zo kunt u de GPU op andere manieren voor u laten werken. Ik neem aan dat CUDA vergelijkbaar is met dat aspect, maar ik heb nooit de kans gehad om ermee te werken.
We hebben het hele onderwerp maar een beetje aangeraakt. 3D grafische programmering is een hel van een beest.
Afbeeldingsbron
Heb je iets toe te voegen aan de uitleg? Geluid uit in de reacties. Wilt u meer antwoorden van andere technisch onderlegde Stack Exchange-gebruikers lezen? Bekijk hier de volledige discussiethread.