Din computers Central Processing Unit (CPU) og Graphics Processing Unit (GPU) interagerer hvert øjeblik, du bruger din computer til at levere dig en skarp og lydhør visuel grænseflade. Læs videre for bedre at forstå, hvordan de arbejder sammen.
Foto af sskennel .
Dagens Spørgsmål og svar-session kommer til os med tilladelse fra SuperUser - en underafdeling af Stack Exchange, en gruppedrevsgruppe af Q & A-websteder.
Spørgsmålet
SuperUser-læser Sathya stillede spørgsmålet:
Her kan du se et skærmbillede af et lille C ++ - program kaldet Triangle.exe med en roterende trekant baseret på OpenGL API.
Ganske vist et meget grundlæggende eksempel, men jeg synes, det kan anvendes til andre grafikkortoperationer.
Jeg var bare nysgerrig og ville gerne vide hele processen fra at dobbeltklikke på Triangle.exe under Windows XP, indtil jeg kan se trekanten rotere på skærmen. Hvad sker der, hvordan interagerer CPU (som først håndterer .exe) og GPU (som til sidst udsender trekanten på skærmen)?
Jeg gætter på, at involveret i visning af denne roterende trekant primært er følgende hardware / software blandt andre:
Hardware
- HDD
- Systemhukommelse (RAM)
- CPU
- Videohukommelse
- GPU
- LCD-skærm
Software
- Operativ system
- DirectX / OpenGL API
- Nvidia Driver
Kan nogen forklare processen, måske med en slags rutediagram til illustration?
Det bør ikke være en kompleks forklaring, der dækker hvert eneste trin (gætte, der ville gå ud over omfanget), men en forklaring, som en mellemliggende it-fyr kan følge.
Jeg er ret sikker på, at mange mennesker, der endda kalder sig it-fagfolk, ikke kunne beskrive denne proces korrekt.
Svaret
Selvom flere medlemmer af samfundet besvarede spørgsmålet, gik Oliver Salzburg den ekstra mil og besvarede det ikke kun med et detaljeret svar, men fremragende ledsagende grafik.
Billede af JasonC, fås som tapet her .
Han skriver:
Jeg besluttede at skrive lidt om programmeringsaspektet og hvordan komponenter taler med hinanden. Måske kaster det lys over bestemte områder.
Præsentationen
Hvad skal der til for at have det eneste billede, som du har sendt i dit spørgsmål, tegnet på skærmen?
Der er mange måder at tegne en trekant på skærmen. Lad os for enkelhedens skyld antage, at der ikke blev brugt vertexbuffere. (EN toppunktbuffer er et hukommelsesområde, hvor du gemmer koordinater.) Lad os antage, at programmet simpelthen fortalte den grafiske behandlingsrørledning om hvert enkelt toppunkt (et toppunkt er bare en koordinat i rummet) i træk.
Men , inden vi kan tegne noget, skal vi først køre stilladser. Vi får at se hvorfor senere:
// Ryd skærmen og dybdebufferen glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Nulstil den aktuelle modelvisningsmatrix glMatrixMode (GL_MODELVIEW); glLoadIdentity (); // Tegning ved hjælp af trekanter glBegin (GL_TRIANGLES); // Rød glColor3f (1.0f, 0.0f, 0.0f); // Top Of Triangle (forside) glVertex3f (0.0f, 1.0f, 0.0f); // Grøn glColor3f (0,0f, 1,0f, 0,0f); // Venstre af trekant (foran) glVertex3f (-1.0f, -1.0f, 1.0f); // Blå glColor3f (0,0f, 0,0f, 1,0f); // Right Of Triangle (forside) glVertex3f (1.0f, -1.0f, 1.0f); // Udført tegning glEnd ();
Så hvad gjorde det?
Når du skriver et program, der ønsker at bruge grafikkortet, vælger du normalt en slags interface til driveren. Nogle kendte grænseflader til føreren er:
- OpenGL
- Direkte3D
- MIRAKLER
I dette eksempel holder vi os til OpenGL. Nu, din interface til driveren er det, der giver dig alle de værktøjer, du har brug for til at lave dit program tale til grafikkortet (eller driveren, som derefter samtaler til kortet).
Denne grænseflade er bundet til at give dig visse værktøjer . Disse værktøjer har form af en BRAND som du kan ringe fra dit program.
Denne API er det, vi ser brugt i eksemplet ovenfor. Lad os se nærmere på.
Stilladset
Inden du virkelig kan tegne en egentlig tegning, skal du udføre en Opsætning . Du skal definere din visningsport (det område, der rent faktisk gengives), dit perspektiv ( kamera ind i din verden), hvilken anti-aliasing du vil bruge (for at udjævne kanterne af din trekant) ...
Men vi vil ikke se på noget af det. Vi kigger bare på de ting, du skal gøre hver ramme . Synes godt om:
Rydning af skærmen
Grafikrørledningen vil ikke rydde skærmen for dig hver ramme. Du bliver nødt til at fortælle det. Hvorfor? Dette er grunden til:
Hvis du ikke rydder skærmen, gør du det ganske enkelt
trække over
det hver ramme. Derfor ringer vi
glClear
med
GL_COLOR_BUFFER_BIT
sæt. Den anden bit (
GL_DEPTH_BUFFER_BIT
) beder OpenGL om at rydde
dybde
buffer. Denne buffer bruges til at bestemme, hvilke pixels der er foran (eller bag) andre pixels.
Transformation
Transformation er den del, hvor vi tager alle inputkoordinaterne (vinklerne i vores trekant) og anvender vores ModelView-matrix. Dette er den matrix, der forklarer hvordan vores model (hjørnerne) roteres, skaleres og oversættes (flyttes).
Dernæst anvender vi vores projektionsmatrix. Dette flytter alle koordinater, så de vender korrekt mod vores kamera.
Nu transformerer vi igen med vores Viewport-matrix. Vi gør dette for at skalere vores model til størrelsen på vores skærm. Nu har vi et sæt hjørner, der er klar til at blive gengivet!
Vi vender tilbage til transformation lidt senere.
Tegning
For at tegne en trekant kan vi simpelthen bede OpenGL om at starte en ny
liste over trekanter
ved at ringe
glBegin
med
GL_TRIANGLES
konstant.
Der er også andre former, du kan tegne. Som en
trekantstrimmel
eller a
trekantventilator
. Disse er primært optimeringer, da de kræver mindre kommunikation mellem CPU'en og GPU'en for at tegne den samme mængde trekanter.
Derefter kan vi give en liste med sæt med 3 hjørner, der skal udgøre hver trekant. Hver trekant bruger 3 koordinater (som vi er i 3D-rum). Derudover giver jeg også en
farve
for hvert toppunkt ved at ringe
glColor3f
Før
ringer
glVertex3f
.
Skyggen mellem de 3 hjørner (de tre hjørner af trekanten) beregnes af OpenGL automatisk . Det interpolerer farven over hele polygonets overflade.
Interaktion
Nu, når du klikker på vinduet. Applikationen skal kun fange vinduesmeddelelse der signaliserer klik. Derefter kan du køre enhver handling i dit program, du ønsker.
Dette får en masse sværere, når du først vil interagere med din 3D-scene.
Du skal først vide tydeligt, hvilken pixel brugeren klikkede på vinduet. Så tag din perspektiv i betragtning kan du beregne retningen af en stråle fra det museklikspunkt ind i din scene. Du kan derefter beregne, om et objekt i din scene krydser hinanden med den stråle . Nu ved du, om brugeren klikkede på et objekt.
Så hvordan får du det til at rotere?
Transformation
Jeg er opmærksom på to typer transformationer, der generelt anvendes:
- Matrixbaseret transformation
- Knoglebaseret transformation
Forskellen er, at knogler påvirker single hjørner . Matricer påvirker altid alle tegnede hjørner på samme måde. Lad os se på et eksempel.
Eksempel
Tidligere har vi indlæst vores identitetsmatrix inden vi tegner vores trekant. Identitetsmatricen er en, der simpelthen giver ingen transformation overhovedet. Så uanset hvad jeg tegner, påvirkes kun af mit perspektiv. Så trekanten roteres slet ikke.
Hvis jeg vil rotere det nu, kunne jeg enten lave matematikken selv (på CPU'en) og bare ringe
glVertex3f
med
Andet
koordinater (som roteres). Eller jeg kunne lade GPU'en gøre alt arbejdet ved at ringe
glRotatef
inden tegning:
// Drej trekanten på Y-aksen glRotatef (mængde, 0,0f, 1,0f, 0,0f);
beløb
er selvfølgelig bare en fast værdi. Hvis du vil
animeret
, skal du holde styr på
beløb
og øg det hver ramme.
Så vent, hvad skete der med al matrix-samtalen tidligere?
I dette enkle eksempel behøver vi ikke bekymre os om matricer. Vi kalder simpelthen
glRotatef
og det tager sig af alt det for os.
glRotatproducerer en rotation afvinkelgrader omkring vektoren x y z. Den aktuelle matrix (se glMatrixMode ) ganges med en rotationsmatrix, hvor produktet erstatter den aktuelle matrix, som om glMultMatrix blev kaldt med følgende matrix som 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
Nå tak for det!
Konklusion
Hvad der bliver tydeligt er, at der er meget snak til OpenGL. Men det fortæller ikke os hvad som helst. Hvor er kommunikationen?
Det eneste, OpenGL fortæller os i dette eksempel, er når det er gjort . Hver operation tager en vis tid. Nogle operationer tager utrolig lang tid, andre er utroligt hurtige.
Afsendelse af et toppunkt til GPU'en vil være så hurtig, at jeg ikke engang ved, hvordan jeg skal udtrykke den. At sende tusinder af hjørner fra CPU'en til GPU'en, hver eneste ramme, er sandsynligvis slet ikke noget problem.
Rydning af skærmen kan tage et millisekund eller værre (husk, du har normalt kun omkring 16 millisekunder tid til at tegne hver ramme), afhængigt af hvor stor din visning er. For at rydde det skal OpenGL tegne hver eneste pixel i den farve, du vil rydde til, det kan være millioner af pixels.
Bortset fra det kan vi stort set kun spørge OpenGL om funktionerne i vores grafikkort (maks. Opløsning, maks. Anti-aliasing, maks. Farvedybde, ...).
Men vi kan også udfylde en struktur med pixels, der hver har en bestemt farve. Hver pixel har således en værdi, og strukturen er en kæmpe "fil" fyldt med data. Vi kan indlæse det på grafikkortet (ved at oprette en teksturbuffer) og derefter indlæse en skygge , fortæl den skygge at bruge vores tekstur som input og køre nogle ekstremt tunge beregninger på vores "fil".
Derefter kan vi "gengive" resultatet af vores beregning (i form af nye farver) til en ny struktur.
Sådan kan du få GPU'en til at fungere for dig på andre måder. Jeg antager, at CUDA udfører svarende til det aspekt, men jeg har aldrig haft mulighed for at arbejde med det.
Vi berørte virkelig kun hele emnet. 3D-grafikprogrammering er et helvedesdyr.
Har du noget at tilføje til forklaringen? Lyder i kommentarerne. Vil du læse flere svar fra andre teknisk kyndige Stack Exchange-brugere? Tjek den fulde diskussionstråd her .