Die Central Processing Unit (CPU) und die Graphics Processing Unit (GPU) Ihres Computers interagieren in jedem Moment, in dem Sie Ihren Computer verwenden, um Ihnen eine gestochen scharfe und reaktionsschnelle visuelle Benutzeroberfläche zu bieten. Lesen Sie weiter, um besser zu verstehen, wie sie zusammenarbeiten.
Die Frage
SuperUser-Leser Sathya stellte die Frage:
Hier sehen Sie einen Screenshot eines kleinen C++-Programms namens Triangle.exe mit einem rotierenden Dreieck basierend auf der OpenGL-API.

Zugegeben, ein sehr einfaches Beispiel, aber ich denke, es ist auf andere Grafikkartenoperationen anwendbar.
Ich war nur neugierig und wollte den gesamten Vorgang vom Doppelklick auf Triangle.exe unter Windows XP kennen, bis ich das Dreieck auf dem Monitor sehen kann. Was passiert, wie interagieren CPU (die zuerst die .exe verarbeitet) und GPU (die schließlich das Dreieck auf dem Bildschirm ausgibt)?
Ich denke, an der Anzeige dieses rotierenden Dreiecks ist unter anderem hauptsächlich die folgende Hardware / Software beteiligt:
Hardware
- HDD
- Systemspeicher (RAM)
- Zentralprozessor
- Videospeicher
- GPU
- LCD Bildschirm
Software
- Betriebssystem
- DirectX/OpenGL-API
- Nvidia-Treiber
Kann jemand den Prozess erklären, vielleicht mit einer Art Flussdiagramm zur Veranschaulichung?
Es sollte keine komplexe Erklärung sein, die jeden einzelnen Schritt abdeckt (glaube, das würde den Rahmen sprengen), sondern eine Erklärung, der ein erfahrener IT-Mitarbeiter folgen kann.
Ich bin mir ziemlich sicher, dass viele Leute, die sich selbst als IT-Profis bezeichnen würden, diesen Prozess nicht richtig beschreiben könnten.
Die Antwort

Obwohl mehrere Community-Mitglieder die Frage beantworteten, ging Oliver Salzburg die Extrameile und beantwortete sie nicht nur mit einer ausführlichen Antwort, sondern auch mit einer hervorragenden begleitenden Grafik.
Er schreibt:
Ich beschloss, ein wenig über den Aspekt der Programmierung zu schreiben und wie Komponenten miteinander kommunizieren. Vielleicht bringt es etwas Licht in bestimmte Bereiche.
Die Präsentation
Was braucht es, damit das einzelne Bild, das Sie in Ihrer Frage gepostet haben, überhaupt auf den Bildschirm gezeichnet wird?
Es gibt viele Möglichkeiten, ein Dreieck auf dem Bildschirm zu zeichnen. Nehmen wir der Einfachheit halber an, dass keine Vertex-Puffer verwendet wurden. (A ist ein Speicherbereich, in dem Sie Koordinaten speichern.) Nehmen wir an, das Programm teilt der Grafikverarbeitungspipeline einfach jeden einzelnen Scheitelpunkt (ein Scheitelpunkt ist nur eine Koordinate im Raum) in einer Reihe mit.
Aber, bevor wir etwas zeichnen können, müssen wir zuerst ein Gerüst bauen. Wir werden später sehen:
// 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();
Also, was hat das bewirkt?
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:
Für dieses Beispiel bleiben wir bei OpenGL. Jetzt erhalten Sie alle Werkzeuge, die Sie benötigen, um Ihr Programm auf die Grafikkarte (oder den Treiber, der dann auf die Karte übertragen wird) zu machen.
Diese Schnittstelle gibt Ihnen bestimmt gewisse . Diese Werkzeuge haben die Form eines API die Sie aus Ihrem Programm aufrufen können.
Diese API wird im obigen Beispiel verwendet. Lasst uns genauer hinschauen.
Das Gerüst
Bevor Sie wirklich zeichnen können, müssen Sie eine . Sie müssen Ihr Ansichtsfenster (den Bereich, der tatsächlich gerendert wird), Ihre Perspektive (die in Ihre Welt) definieren, welches Anti-Aliasing Sie verwenden (um die Kanten Ihres Dreiecks zu glätten)…
Aber wir werden uns das alles nicht ansehen. Wir werfen nur einen Blick auf die Dinge, die Sie tun müssen jeder Rahmen. Mögen:
Bildschirm leeren
Die Grafikpipeline wird den Bildschirm nicht für jeden Frame leeren. Sie müssen es erzählen. Wieso den? Aus diesem Grund:

Wenn Sie den Bildschirm nicht löschen, werden Sie ihn einfach bei jedem Frame löschen. Deshalb rufen wir an glClear
mit demGL_COLOR_BUFFER_BIT
einstellen. Das andere Bit (GL_DEPTH_BUFFER_BIT
) weist OpenGL an, den Puffer zu löschen. 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, wie unsere (die Scheitelpunkte) gedreht, skaliert und verschoben (bewegt) werden.
Als nächstes wenden wir unsere Projektionsmatrix an. Dadurch werden alle Koordinaten so verschoben, dass sie unserer Kamera richtig zugewandt sind.
Jetzt transformieren wir noch einmal mit unserer Viewport-Matrix. Wir tun dies, um unsere auf die Größe unseres Monitors zu skalieren. Jetzt haben wir eine Reihe von Scheitelpunkten, die gerendert werden können!
Wir kommen etwas später auf die Transformation zurück.
Zeichnung
Um ein Dreieck zu zeichnen, können wir OpenGL einfach anweisen, ein neues zu beginnen Liste der Dreiecke per Anruf glBegin
mit dem GL_TRIANGLES
Konstante.
Es gibt auch andere Formen, die Sie zeichnen können. Wie ein Dreiecksstreifen oder ein Dreiecksfächer. Dies sind in erster Linie Optimierungen, da sie weniger Kommunikation zwischen CPU und GPU erfordern, um die gleiche Anzahl von Dreiecken zu zeichnen.
Danach können wir eine Liste von Sätzen von 3 Scheitelpunkten bereitstellen, die jedes Dreieck bilden sollen. Jedes Dreieck verwendet 3 Koordinaten (da wir uns im 3D-Raum befinden). Darüber hinaus stelle ich auch eine für jeden Scheitelpunkt bereit, indem ich anrufeglColor3f
Vor Berufung glVertex3f
.
Der Schatten zwischen den 3 Eckpunkten (den 3 Ecken des Dreiecks) wird von OpenGL berechnetautomatisch. Es interpoliert die Farbe über die gesamte Fläche des Polygons.
Interaktion
Jetzt, wenn Sie auf das Fenster klicken. Die Anwendung muss nur die Fensternachricht das signalisiert das Klicken. Dann können Sie jede gewünschte Aktion in Ihrem Programm ausführen.
Das wird a Menge schwieriger, wenn Sie mit der Interaktion mit Ihrer 3D-Szene beginnen möchten.
Zunächst muss klar sein, an welchem Pixel der Benutzer auf das Fenster geklickt hat. Unter Berücksichtigung Ihrer können Sie dann die Richtung eines Strahls berechnen, vom Punkt des Mausklicks in Ihre Szene. Sie können dann berechnen, ob ein Objekt in Ihrer Szene mit diesem Strahl. Jetzt wissen Sie, ob der Benutzer auf ein Objekt geklickt hat.
Also, wie bringt man es zum Rotieren?
Transformation
Mir sind zwei Arten von Transformationen bekannt, die im Allgemeinen angewendet werden:
- Matrixbasierte Transformation
- Knochenbasierte Transformation
Der Unterschied besteht darin, dass einzelne betroffen sind. Matrizen wirken sich immer auf alle gezeichneten Scheitelpunkte gleich aus. Schauen wir uns ein Beispiel an.
Beispiel
Vorhin haben wir unsere . geladen bevor Sie unser Dreieck zeichnen. Die Identitätsmatrix liefert einfach keine Verwandlung überhaupt. Was auch immer ich zeichne, wird also 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
mit Koordinaten (die gedreht werden). Oder ich könnte die GPU die ganze Arbeit machen lassen, indem ich anrufe glRotatef
vor dem Zeichnen:
// Rotate The Triangle On The Y axis glRotatef(amount,0.0f,1.0f,0.0f);
amount
ist natürlich nur ein fester Wert. Wenn du willst, musst du den Überblick behalten amount
und erhöhen Sie es mit jedem Frame.
Also, warte, was ist mit dem ganzen Matrix-Gespräch vorhin passiert?
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 von angle
Grad um den Vektor xyz . Die aktuelle Matrix (sieheglMatrixModus) wird mit einer Rotationsmatrix multipliziert, wobei das Produkt die aktuelle Matrix ersetzt, als obglMultMatrix wurden mit der folgenden Matrix als Argument aufgerufen:
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
Nun, danke dafür!
Abschluss
Was offensichtlich wird ist, es wird viel geredet zu OpenGL. Aber es sagt nichts uns irgendetwas. Wo ist die Kommunikation?
Das einzige, was uns OpenGL in diesem Beispiel sagt, ist . Jede Operation nimmt eine gewisse Zeit in Anspruch. Manche Operationen dauern unglaublich lange, andere sind unglaublich schnell.
zur GPU wird so schnell sein, ich wüsste gar nicht, wie ich es ausdrücken soll. Das Senden von Tausenden von Vertices von der CPU an die GPU, jeden einzelnen Frame, ist höchstwahrscheinlich überhaupt kein Problem.
kann eine Millisekunde oder schlimmer dauern (denken Sie daran, dass Sie normalerweise nur etwa 16 Millisekunden Zeit haben, um jedes Bild zu zeichnen), je nachdem, wie groß Ihr Ansichtsfenster ist. Um es zu löschen, muss OpenGL jedes einzelne Pixel in der Farbe zeichnen, die Sie löschen möchten, das können Millionen von Pixeln sein.
Ansonsten können wir OpenGL so ziemlich nur nach den Fähigkeiten unserer Grafikkarte fragen (maximale Auflösung, maximale Kantenglättung, maximale Farbtiefe, …).
Wir können eine Textur aber auch mit Pixeln füllen, die jeweils eine bestimmte Farbe haben. Jedes Pixel enthält somit einen Wert und die Textur ist eine riesige „Datei“, die mit Daten gefüllt ist. Wir können das in die Grafikkarte laden (indem wir einen Texturpuffer erstellen), dann laden Sie a Shader, weisen Sie diesen Shader an, unsere Textur als Eingabe zu verwenden, und führen Sie einige extrem schwere Berechnungen für unsere «Datei» durch.
Das Ergebnis unserer Berechnung (in Form neuer Farben) können wir dann in eine neue Textur „rendern“.
Auf diese Weise können Sie die GPU auf andere Weise für sich 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. 3D-Grafikprogrammierung ist eine Hölle von einem Biest.

Bildquelle