Wie interagieren CPU und GPU, um Computergrafik zu rendern?
Die zentrale Prozessoreinheit (CPU) und die Grafikprozessoreinheit (GPU) Ihres Computers interagieren in jedem Moment, in dem Sie Ihren Computer verwenden, und bieten Ihnen eine scharfe und ansprechende visuelle Schnittstelle. Lesen Sie weiter, um besser zu verstehen, wie sie zusammenarbeiten.
Foto von Sskennel.
Die heutige Question & Answer-Sitzung wird von SuperUser zur Verfügung gestellt - einer Unterteilung von Stack Exchange, einer Community-Gruppe von Q & A-Websites.
Die Frage
Superuser-Leser Sathya stellte die Frage:
Hier sehen Sie einen Screenshot eines kleinen C ++ - Programms namens Triangle.exe mit einem Dreieck, das auf der OpenGL-API basiert.
Zugegebenermaßen ein sehr einfaches Beispiel, aber ich denke, es ist auf andere Grafikkartenvorgänge anwendbar.
Ich war nur neugierig und wollte den gesamten Prozess durch Doppelklicken auf Triangle.exe unter Windows XP wissen, bis ich das Dreieck auf dem Monitor drehen kann. Was passiert, wie interagieren CPU (die zuerst mit der EXE-Datei umgeht) und GPU (die schließlich das Dreieck auf dem Bildschirm ausgibt)??
Ich denke, bei der Darstellung dieses Dreiecks handelt es sich unter anderem um folgende Hardware / Software:
Hardware
- HDD
- Systemspeicher (RAM)
- Zentralprozessor
- Videospeicher
- GPU
- LCD Bildschirm
Software
- Betriebssystem
- DirectX / OpenGL-API
- Nvidia-Fahrer
Kann jemand den Prozess erklären, vielleicht mit einer Art Flussdiagramm zur Veranschaulichung?
Es sollte sich nicht um eine komplexe Erklärung handeln, die jeden einzelnen Schritt abdeckt (eine Vermutung, die über den Rahmen hinausgehen würde), sondern eine Erklärung, die ein IT-Intermediär folgen kann.
Ich bin mir ziemlich sicher, dass viele Leute, die sich selbst als IT-Experten bezeichnen würden, diesen Prozess nicht richtig beschreiben könnten.
Die Antwort
Obwohl mehrere Community-Mitglieder auf die Frage geantwortet haben, hat Oliver Salzburg nicht nur eine ausführliche Antwort, sondern auch hervorragende Begleitgrafiken erhalten.
Bild von JasonC, hier als Hintergrundbild verfügbar.
Er schreibt:
Ich beschloss, etwas über den Programmieraspekt zu schreiben und wie Komponenten miteinander kommunizieren. Vielleicht werden einige Bereiche beleuchtet.
Die Präsentation
Was braucht es, um dieses einzelne Bild, das Sie in Ihrer Frage gepostet haben, überhaupt auf dem Bildschirm zeichnen zu lassen??
Es gibt viele Möglichkeiten, ein Dreieck auf dem Bildschirm zu zeichnen. Nehmen wir zur Vereinfachung an, dass keine Scheitelpunktpuffer verwendet wurden. (EIN Scheitelpunktpufferist ein Speicherbereich, in dem Sie Koordinaten speichern.) Angenommen, das Programm teilt der Grafikverarbeitungspipeline einfach jeden einzelnen Scheitelpunkt (ein Scheitelpunkt ist nur eine Koordinate im Raum) in einer Zeile mit.
Aber, Bevor wir etwas zeichnen können, müssen wir zuerst ein Gerüst bauen. Wir werden sehen Warum später:
// Bildschirm und Tiefenpuffer löschen glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Die aktuelle Modelview-Matrix zurücksetzen glMatrixMode (GL_MODELVIEW); glLoadIdentity (); // Zeichnen mit Dreiecken glBegin (GL_TRIANGLES); // Rot glColor3f (1.0f, 0.0f, 0.0f); // Top Of Triangle (Vorderseite) glVertex3f (0.0f, 1.0f, 0.0f); // Green glColor3f (0,0f, 1,0f, 0,0f); // Left Of Triangle (Vorderseite) glVertex3f (-1.0f, -1.0f, 1.0f); // Blue glColor3f (0,0f, 0,0f, 1,0f); // Right Of Triangle (Vorderseite) glVertex3f (1.0f, -1.0f, 1.0f); // Fertig Zeichnung glEnd ();
Also, was hat das getan??
Wenn Sie ein Programm schreiben, das die Grafikkarte verwenden möchte, wählen Sie normalerweise eine Art Schnittstelle zum Treiber. Einige bekannte Schnittstellen zum Treiber sind:
- OpenGL
- Direct3D
- CUDA
Für dieses Beispiel bleiben wir bei OpenGL. Nun, dein Schnittstelle zum Treiber Dies ist, was Ihnen alle Werkzeuge gibt, die Sie zur Erstellung Ihres Programms benötigen sich unterhalten auf die Grafikkarte (oder den Treiber, der dann Gespräche zur karte).
Diese Schnittstelle gibt Ihnen bestimmt Sicherheit Werkzeuge. Diese Tools haben die Form einer API, die Sie von Ihrem Programm aus aufrufen können.
Diese API wird im obigen Beispiel verwendet. Lass uns genauer hinschauen.
Das Gerüst
Bevor Sie wirklich zeichnen können, müssen Sie eine Konfiguration. Sie müssen Ihr Ansichtsfenster (den Bereich, der tatsächlich gerendert wird) und Ihre Perspektive definieren Kamera in Ihre Welt), welches Anti-Aliasing Sie verwenden werden (um die Kanten Ihres Dreiecks zu glätten)…
Aber wir werden uns das nicht ansehen. Wir werfen einen Blick auf das, was Sie tun müssen jeder Frame. Mögen:
Bildschirm löschen
Die Grafik-Pipeline wird den Bildschirm nicht für jeden Frame löschen. Du musst es sagen. Warum? Deshalb:
Wenn Sie den Bildschirm nicht löschen, werden Sie dies einfach tun Überziehen es jeden Frame. Deshalb rufen wir an glClear
mit demGL_COLOR_BUFFER_BIT
einstellen. Das andere bisschen (GL_DEPTH_BUFFER_BIT
) weist OpenGL an, das zu löschen TiefePuffer. Dieser Puffer wird verwendet, um zu bestimmen, welche Pixel vor (oder hinter) anderen Pixeln liegen.
Transformation
Bildquelle
Transformation ist der Teil, in dem wir alle Eingabekoordinaten (die Eckpunkte unseres Dreiecks) nehmen und unsere ModelView-Matrix anwenden. Dies ist die Matrix der erklärt wie unser Modell- (die Scheitelpunkte) werden gedreht, skaliert und verschoben (verschoben).
Als nächstes wenden wir unsere Projektionsmatrix an. Dadurch werden alle Koordinaten so verschoben, dass sie unserer Kamera korrekt gegenüberliegen.
Jetzt verwandeln wir uns noch einmal mit unserer Viewport-Matrix. Wir tun dies, um unser zu skalieren Modell- auf die Größe unseres Monitors. Jetzt haben wir eine Reihe von Scheitelpunkten, die gerendert werden können!
Wir werden später etwas zurückkehren.
Zeichnung
Um ein Dreieck zu zeichnen, können wir OpenGL einfach mitteilen, dass er ein neues beginnen soll Liste der Dreiecke durch anrufen glBegin
mit dem GL_TRIANGLES
Konstante.
Es gibt auch andere Formen, die Sie zeichnen können. Wie ein Dreieckstreifen oder ein Dreieckfächer. Dies sind in erster Linie Optimierungen, da sie weniger Kommunikation zwischen der CPU und der GPU erfordern, um die gleiche Anzahl von Dreiecken zu zeichnen.
Danach können wir eine Liste von drei Scheitelpunkten bereitstellen, aus denen jedes Dreieck bestehen soll. Jedes Dreieck verwendet 3 Koordinaten (da wir uns im 3D-Raum befinden). Zusätzlich stelle ich auch eine Farbe für jeden Scheitelpunkt durch AufrufenglColor3f
Vor Berufung glVertex3f
.
Die Schattierung zwischen den 3 Eckpunkten (den drei Ecken des Dreiecks) wird von OpenGL berechnetautomatisch. Die Farbe wird über die gesamte Fläche des Polygons interpoliert.
Interaktion
Wenn Sie jetzt auf das Fenster klicken. Die Anwendung muss nur die Fenstermeldung erfassen, die den Klick signalisiert. Dann können Sie eine beliebige Aktion in Ihrem Programm ausführen.
Das bekommt ein Menge schwieriger, sobald Sie mit Ihrer 3D-Szene interagieren möchten.
Sie müssen zunächst klar wissen, bei welchem Pixel der Benutzer auf das Fenster geklickt hat. Dann nehmen Sie Ihre PerspektiveUnter Berücksichtigung können Sie die Richtung eines Strahls vom Mausklick in Ihre Szene berechnen. Sie können dann berechnen, ob sich ein Objekt in Ihrer Szene befindet schneidet mit diesem Strahl Jetzt wissen Sie, ob der Benutzer auf ein Objekt geklickt hat.
Also, wie lässt du es drehen??
Transformation
Mir sind zwei Arten von Transformationen bekannt, die im Allgemeinen angewendet werden:
- Matrixbasierte Transformation
- Knochenbasierte Transformation
Der Unterschied ist das Knochen Einzelne beeinflussen Scheitelpunkte. Matrizen wirken sich immer auf alle gezeichneten Scheitelpunkte auf dieselbe Weise aus. Schauen wir uns ein Beispiel an.
Beispiel
Früher haben wir unsere geladen Identitätsmatrix bevor Sie unser Dreieck zeichnen. Die Identitätsmatrix liefert einfach keine Verwandlung überhaupt. Was immer ich zeichne, wird nur von meiner Perspektive beeinflusst. Das Dreieck wird also überhaupt nicht gedreht.
Wenn ich es jetzt drehen möchte, könnte ich entweder selbst rechnen (auf der CPU) und einfach anrufen glVertex3f
mitandere Koordinaten (die gedreht werden). Oder ich könnte die GPU die ganze Arbeit machen lassen, indem ich anrufe glRotatef
vor dem Zeichnen:
// Dreieck auf der Y-Achse drehen glRotatef (Betrag 0,0f, 1,0f, 0,0f);
Menge
ist natürlich nur ein fester Wert. Wenn du möchtest animieren, Sie müssen den Überblick behalten Menge
und vergrößere es jeden Frame.
Warten Sie also, was früher mit allen Matrixgesprächen passiert ist?
In diesem einfachen Beispiel müssen wir uns nicht um Matrizen kümmern. Wir rufen einfach an glRotatef
und es kümmert sich um all das für uns.
glRotate
erzeugt eine Drehung vonWinkel
Grad um den Vektor x y z. Die aktuelle Matrix (seeglMatrixMode) wird mit einer Rotationsmatrix multipliziert, wobei das Produkt die aktuelle Matrix ersetzt, da ifglMultMatrix mit der folgenden Matrix als Argument aufgerufen wurde:x 2 - 1 - c + cx - y - 1 - c - z - sx - z - 1 - c + y - 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
Vielen Dank dafür!
Fazit
Es wird offensichtlich, dass viel geredet wird zu OpenGL. Aber es sagt nichts uns etwas. Wo ist die Kommunikation??
Das einzige, was uns OpenGL in diesem Beispiel sagt, ist wenn es fertig ist. Jede Operation dauert eine gewisse Zeit. Manche Operationen dauern unglaublich lange, andere sind unglaublich schnell.
Scheitelpunkt senden Die GPU wird so schnell sein, dass ich nicht einmal wissen würde, wie ich sie ausdrücken soll. Das Senden tausender Scheitelpunkte von der CPU an die GPU, jedes einzelne Frame, ist höchstwahrscheinlich überhaupt kein Problem.
Bildschirm löschen Es kann eine Millisekunde dauern oder schlechter (bedenken Sie, dass Sie normalerweise nur etwa 16 Millisekunden Zeit haben, um jeden Frame zu zeichnen), je nachdem, wie groß Ihr Ansichtsfenster ist. Um es zu löschen, muss OpenGL jedes einzelne Pixel in der Farbe zeichnen, in der Sie löschen möchten, dh Millionen Pixel.
Abgesehen davon können wir OpenGL so gut wie nur nach den Fähigkeiten unseres Grafikadapters fragen (maximale Auflösung, maximales Anti-Aliasing, maximale Farbtiefe,…)..
Wir können eine Textur aber auch mit Pixeln füllen, die jeweils eine bestimmte Farbe haben. Jedes Pixel enthält also einen Wert und die Textur ist eine riesige "Datei", die mit Daten gefüllt ist. Wir können das in die Grafikkarte laden (durch Erstellen eines Texturpuffers), dann einen Shader laden, diesen Shader anweisen, unsere Textur als Eingabe zu verwenden, und einige extrem schwere Berechnungen an unserer „Datei“ ausführen..
Dann können wir das Ergebnis unserer Berechnung (in Form neuer Farben) in eine neue Textur „umwandeln“.
So können Sie die GPU auf andere Weise für Sie arbeiten lassen. Ich gehe davon aus, dass CUDA diesem Aspekt ähnlich ist, aber ich hatte nie die Gelegenheit, damit zu arbeiten.
Wir haben das ganze Thema wirklich nur wenig berührt. Die Programmierung von 3D-Grafiken ist eine Hölle.
Bildquelle
Haben Sie der Erklärung etwas hinzuzufügen? Ton aus in den Kommentaren. Möchten Sie mehr Antworten von anderen technisch versierten Stack Exchange-Benutzern lesen? Hier geht es zum vollständigen Diskussionsthread.