Ich recherchiere, wie die meisten hardwarebeschleunigten GUI-Bibliotheken funktionieren. Ich kümmere mich eigentlich nur um die Rendering-Backends von ihnen hier. Ich versuche herauszufinden, was der beste Weg wäre, mein eigenes als eine Art Nebenprojekt zu schreiben. Ich versuche hier ultimative Leistung zu erzielen, anstatt übermäßig ausgefallene Funktionen. Ich möchte Primitive, Text und Animationen zeichnen können.
Einige gute Bibliotheken, die ich kenne, sind Qt, Skia und Kairo (obwohl ich nicht sicher bin, wie der Zustand von HWA darauf ist). Ich habe mir auch NanoVG angesehen, eine kleine Bibliothek, die eine anständige Anhängerschaft zu haben scheint. Ich habe es aber nicht geschafft, mit NanoVG eine anständige Leistung zu erzielen ...
Das einzige, was mir aufgefallen ist, war, dass all diese Bibliotheken das Konzept der "Malerei" zu verwenden scheinen, bei dem es scheint, dass jede primitive Form immer wieder von Grund auf neu gezeichnet wird. Damit meine ich, dass es aus den APIs nicht so aussieht, als ob die Formen als "Objekte" auf der GPU oder wie auch immer die Terminologie erstellt und dann "automatisch" gerendert wird. Mit anderen Worten, sie verbleiben nicht im Speicher der GPU, um in einer großen Schleife neu gezeichnet zu werden. Um es näher zu erläutern, scheint es, dass für jedes zu zeichnende Rechteck ein ganzer OpenGL-Status eingerichtet wird, nur um dieses Rechteck zu rendern, und dann wieder zerstört wird. Es sieht jedoch so aus, als würden diese gerenderten Formen zumindest an ihren endgültigen Zielen gerendert, sodass die GPU dann die gesamte Szene zusammenstellen kann.
Ich habe erwartet, dass diese Bibliotheken funktionieren, indem ich die gesamte Szene auf der GPU speichere (entschuldigen Sie die schreckliche Terminologie). Zum Beispiel würden Grundelemente trianguliert und im Speicher belassen, wo nach einem komplizierten Prozess eine Haupt-Rendering-Schleife für die Szene erstellt würde. Darüber hinaus wären dann Mechanismen vorhanden, um Attribute zu aktualisieren oder Grundelemente zu löschen oder hinzuzufügen. Dies ist eine ziemlich vage Beschreibung, aber ich denke, dass Sie auf die Idee kommen.
Was ich jetzt fragen möchte, ist, ob der "Mal" -Ansatz im Vergleich zum "gespeicherten" Ansatz einen Leistungsvorteil hat (wiederum keine Ahnung, ob es Eigennamen für diese Dinge gibt ...). Vielleicht einige komplizierte Caching-Mechanismen? Oder ist es einfach viel einfacher, damit zu arbeiten?
Mir ist klar, dass der "gespeicherte" Ansatz möglicherweise mehr Speicher auf der GPU benötigt, aber sind alle OpenGL-Aufrufe, die für den "Mal" -Ansatz benötigt werden, nicht sehr teuer? Ich denke, man kann dies möglicherweise durch Zwischenspeichern der gerenderten Formen kompensieren, aber bietet die GPU wirklich einen so großen Vorteil, wenn eine solche einmalige (oder nicht sehr regelmäßige) Rasterung im Vergleich zur CPU durchgeführt wird, insbesondere angesichts der Kommunikation Overhead? Stellt dieser Kommunikationsaufwand keine ernsthaften Probleme für Animationen dar, wenn für jeden Frame gezeichnet werden muss?
Ich bin mir ziemlich sicher, dass NanoVG keinen internen Caching-Mechanismus hat, und ich würde annehmen, dass dies für seine eher mangelhafte Leistung verantwortlich sein könnte. Qt hingegen scheint eine hervorragende Leistung zu haben, daher muss es etwas richtig machen. Google scheint auch in der Lage zu sein, Skia gut zu nutzen.
PS. Ich bin kein Profi und habe erst vor kurzem angefangen, OpenGL zu lernen.
EDIT: Eine andere Möglichkeit, an die ich gedacht habe, ist, dass vielleicht der "Mal" -Ansatz nur wegen der Gedächtnisvorteile als notwendig erachtet wurde? Der Grund, warum ich denke, ist, dass all diese Bibliotheken natürlich in einer anderen Ära gestartet wurden und auch auf eingebettete Plattformen abzielen, was bedeutet, dass der GPU-Speicher auf den Zielplattformen (ed) so knapp sein könnte und dass möglicherweise so wenig wie möglich davon verwendet wird wichtiger als Leistung. In einer solchen Situation bin ich jedoch nicht davon überzeugt, dass eine rahmenweise GPU-Rasterung angesichts des Kommunikationsaufwands eine CPU übertreffen wird, insbesondere angesichts der wahrscheinlich geringen Pixelanzahl auf Plattformen mit so wenig Speicher.
Außerdem habe ich auf http://blog.qt.io/blog/2010/01/06/qt-graphics-and-performance-opengl/ gelesen, dass Qt anscheinend Shader-Code aus vorcodierten Segmenten zur Laufzeit vor dem "Malen" und zusammenmischt hofft dann, dass der OGL-Compiler den Code zur Laufzeit richtig einbindet. Das klingt für mich nach noch mehr OGL-Initialisierungsaufwand ...
Antworten:
Das Speichern des gesamten Fensters als einzelnes Objekt in der GPU (es wären mehrere Rechtecke, die als VBO gespeichert werden) und das anschließende Rendern in einem einzelnen OpenGL-Draw-Aufruf wäre schnell, hat jedoch mehrere Nachteile:
Wenn Sie es in mehrere Objekte aufteilen, erhalten Sie schließlich einzelne oder wenige Rechtecke pro Objekt. Es ist einfacher und schneller, sie ohne gespeicherte Objekte zu rendern.
GUI-Frameworks verfolgen, welche genauen Teile des Fensters geändert wurden, und malen nur diese neu. Das alte Image wird in der GPU zwischengespeichert. Dieser Ansatz kann mit verschiedenen Zeichnungs-Backends verwendet werden, nicht nur mit OpenGL / DirectX-beschleunigtem Rendering.
Wenn Sie ein Beispiel für eine GUI-Bibliothek überprüfen möchten, die Geometrien generiert, die Sie in OpengGL (oder in eine andere 3D-API) einspeisen können , sehen Sie sich librocket an . Es kann tatsächlich statische Geometrien zusammen backen und sie in einem einzigen Zeichnungsaufruf rendern, aber jedes Element, das sich häufig ändert oder mit einem eigenen Shader gerendert werden muss, muss getrennt bleiben.
quelle