Connect with us

Wie man

Wie interagieren CPU und GPU beim Rendern von Computergrafiken?

Wie interagieren CPU und GPU beim Rendern von Computergrafiken?

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 glRotatefvor 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 amountund 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

Continue Reading
Click to comment

Leave a Reply

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Tendencia