Autor Thema: App-/GUI-Server  (Gelesen 25078 mal)

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #40 am: 23. November 2010, 17:17 »
Auch wenn es noch in weiter Ferne liegt würde ich mal ein paar Ideen zu einem GUI Konzept sammeln/austauschen wollen.

Also erstmal muss ich sagen, das ich von grafischer Programmierung noch gar keine Ahnung habe.

Aus aktuellem Anlass ("Untergang" vom X-Server) muss ich wohl mein geplantes Konzept nochmal überdenken.

Ich wollte es eigentlich auch so machen, das man alles was man zeichnen will als Anfrage an den Server formuliert, aber das produziert natürlich overhead.

Die andere Lösung ist halt, den Fensterinhalt als Bitmap an den GUI-Server zu "schicken" und dieser stellt die Bitmap dann als Fensterinhalt dar (sowas wie Fensterrand und Titelleiste, werden weiterhin vom GUI-Server dargestellt/erstellt).

Welches Konzept ist besser und warum? Vielleicht hat jemand noch eine ganz andere Idee?

Mir geht es vorallem darum, das man ohne großen Aufwand jede App so schreiben kann, das der GUI-Code vom restlichen Code getrennt ist, so dass es nicht passieren kann, dass der Fensterinhalt nicht gezeichnet wird bzw. sich nicht änder/keine Eingaben angenommen werden, nur weil der eigentliche App-Code gerade ausgeführt wird.

Bei der Lösung mit der Bitmap würde ich dann ne Art SDK (so wie die Kits bei Haiku) zur Verfügung stellen, damit alle Programme halbwegs gleich aussehen. Außerdem ist es so einfacher und schneller Fehler in allen Programmen, was die GUI betrifft, zu beseitigen.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #41 am: 23. November 2010, 17:44 »
Es gibt grundsätzlich zwei Möglichkeiten: Indirektes Rendering (X11, der Grafiktreiber/X-Server/... zeichnet den Bildschirm) oder direktes Rendering (Wayland oder DRM/DRI, die Applikation zeichnet den Inhalt selbst). Indirektes Rendering ist überholt. Damit kann man nämlich keine Form der Hardwarebeschleunigung machen. Es bleibt direktes Rendering übrig, also die Anwendungen zeichnen selbst.

Fensterverwaltung sollte man mMn dem System überlassen, denn es muss sich um Dinge wie Fokus kümmern.

Fensterdekoration kann man im System oder in den Anwendungen machen. Machst du es im System, sehen alle Fenster gleich aus, sind zentral konfigurierbar und immer rechteckig (bzw. nicht vollkommen frei in ihrer Form). Machen die Anwendungen es selbst, dann sehen alle Programme unter Umständen verschieden aus, was hässlich ist. Als dritte Möglichkeit baust du eine Library, die die Fensterdekorationen zeichnet und von allen Anwendungen verwendet wird, damit hast du dann wieder ein einheitliches Look & Feel. Da alle Anwendungen ohnehin ein Toolkit (Qt, GTK) benutzen sollten (nicht müssen), kann man das da auch mit einbauen.

Wichtig ist vor überhaupt allem, dass die Fensterdekoration und -verwaltung in einem anderen Task geschieht. Wenn du nämlich Tasks stoppst (oder sie hängen), musst du in der Fensterdekoration auf das X klicken können, um das Fenster zu schließen/den Prozess zu killen und du musst immer in der Lage sein, Fenster zu verschieben. Das kann man in der Dekorationsbibliothek ja direkt abfangen und diese über eine zentrale Konfigurationsdatei auch steuern.

Die grafische Oberfläche implementierst du dann sinnvollerweise als ein eventbasiertes System, die Anwendungen können (müssen aber nicht) dann einen eigenen Thread haben, der dem App-Code die Ereignisse aufbereitet und zuspielt.

Du kannst dir ja mal die Wayland-Mailingliste anschauen, da wird sowas auch diskutiert. Oder du portierst Wayland auf dein OS und beweist damit (a) die Portabilität von Wayland und (b) bist du gleich bleeding edge, was moderne Technologien angeht. ;-)

Ich bin ein Freund der Idee des direkten Renderns, der systemeigenen Fensterverwaltung, der anwendungseigenen Fensterdekoration mit Bibliothek.

;-)

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #42 am: 23. November 2010, 18:18 »
Zitat von: svenska
Indirektes Rendering ist überholt. Damit kann man nämlich keine Form der Hardwarebeschleunigung machen. Es bleibt direktes Rendering übrig, also die Anwendungen zeichnen selbst.
Das verstehe ich nicht, denn ich hätte gedacht das es genau umgedreht ist.

Denn bei direktem Rendering zeichnest du immer in eine Bitmap und "sendest" die an den GUI-Server und der blittet die dann in die große Bildschirm-Bitmap.

Bei indirektem Rendering können aber irgendwelche, vorhandenen, Hardwarefunktionen genutzt werden (Linienzeichnen und Co.).
Auch bietet indirektes Rendering den Vorteil, das man als GUI-Server die Kontrolle über viele Sachen hat und damit sollte sich sowas wie einheitliche Schriftgröße (zwecks Skalierung) einfacher umsetzen lassen.

Ich habe sowieso noch gar keine Vorstellung wie man sowas wie OpenGL am besten umsetzt. Denn das ist ja auch Hardwarebeschleunigung in dem Programm, aber eigentlich ja auch indirektes Rendering, weil du ja der Grafikkarte sagst was wie und wo gezeichnet werden soll und hast damit wieder nen gewissen Overhead, weil du die Daten ja erstmal zum Treiber und der dann zur Grafikkarten senden muss.

Edit::

Einen Vorteil den ich noch für indirektes Rendering sehe, ist dass man keine Nachrichten verschicken muss, wenn sich z.B. die Fenstergröße ändert (oder doch?). Denn eigentlich hat man ja alle Infos die man braucht und kann das Fenster dann vom GUI-Server neu zeichnen lassen.
Ich stelle mir das so vor, das man nicht nur sagt was wo und wie gezeichnet werden soll, sondern das man ne Art Beschreibung wie der Fensterinhalt aussehen soll (ich denke da z.B. an Vektorgrafik) und das alles was mit Verschiebung und Größenänderung zu tun hat, kann der GUI-Server machen.

Oder würde das zu kompliziert, umständlich und langsamen werden?
« Letzte Änderung: 24. November 2010, 09:06 von FlashBurn »

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #43 am: 24. November 2010, 22:19 »

Zitat von: svenska
Indirektes Rendering ist überholt. Damit kann man nämlich keine Form der Hardwarebeschleunigung machen. Es bleibt direktes Rendering übrig, also die Anwendungen zeichnen selbst.
Denn bei direktem Rendering zeichnest du immer in eine Bitmap und "sendest" die an den GUI-Server und der blittet die dann in die große Bildschirm-Bitmap.
Du zeichnest keine Bitmap und sendest die an den GUI-Server, sondern du zeichnest in einen Puffer, der dir vom GUI-Server zur Verfügung gestellt wurde und nutzt dazu Funktionen, die dir vom Grafiktreiber (DRI/DRM) zur Verfügung gestellt werden. Diese Funktionen sind im Prinzip ein OpenGL- (oder DirectX-)Kommandostrom, der von der Grafikkarte direkt verarbeitet wird.

Bei indirektem Rendering können aber irgendwelche, vorhandenen, Hardwarefunktionen genutzt werden (Linienzeichnen und Co.).
Ja, sofern du jede mögliche Hardwarefunktion im Protokoll zwischen GUI-Server und Anwendung definierst. Für einfache 2D-Dinge ist das vollkommen hinreichend (und geht auch bei X11 indirekt), aber für kompliziertere Dinge wie 3D ist das nicht mehr möglich. Insbesondere 3D-Spiele wollen ja die Grafikkarte ausreizen und müssen somit zwangsweise direkt mit dem Grafiktreiber sprechen.

Auch bietet indirektes Rendering den Vorteil, das man als GUI-Server die Kontrolle über viele Sachen hat und damit sollte sich sowas wie einheitliche Schriftgröße (zwecks Skalierung) einfacher umsetzen lassen.
Das kann der GUI-Server durchaus anbieten, aber das Zeichnen sollten die Anwendungen selbst machen. Es geht ja ausschließlich um den Fensterinhalt. Zumal manche Anwendungen durchaus absichtlich keine einheitlichen Schriftgrößen nutzen können oder wollen (v.a. Spiele mit eigener Oberfläche, aber Dinge wie Java-Anwendungen, wo die gesamte Darstellung von der JVM erledigt wird und daher gewisse Randbedingungen gelten müssen).

Ich habe sowieso noch gar keine Vorstellung wie man sowas wie OpenGL am besten umsetzt. Denn das ist ja auch Hardwarebeschleunigung in dem Programm, aber eigentlich ja auch indirektes Rendering, weil du ja der Grafikkarte sagst was wie und wo gezeichnet werden soll und hast damit wieder nen gewissen Overhead, weil du die Daten ja erstmal zum Treiber und der dann zur Grafikkarten senden muss.
Eben darum wird direktes Rendering benutzt. Du bekommst vom GUI-Server nur noch einen Puffer, wo du "reinrendern" musst. Die Daten kannst du mit Pixelschubsen oder 2D-beschleunigten Funktionen da reinkriegen, oder du steuerst die Grafikkarte direkt an.

Edit::

Einen Vorteil den ich noch für indirektes Rendering sehe, ist dass man keine Nachrichten verschicken muss, wenn sich z.B. die Fenstergröße ändert (oder doch?). Denn eigentlich hat man ja alle Infos die man braucht und kann das Fenster dann vom GUI-Server neu zeichnen lassen.
Das hieße, dass du enorme Informationen (Puffer) über den Fensterinhalt im GUI-Server behalten musst. Und zwar für jedes Fenster, egal ob es verdeckt oder außerhalb des Bildschirms ist. Heutzutage möglich, im Falle von X11 war es nicht möglich (zuwenig RAM in den Rechnern).

Kein windowing-System garantiert den Inhalt des Fensters; die Anwendung bekommt immer ein Event, welcher Teil jetzt neu gezeichnet werden muss. Das trifft sowohl direktes als auch indirektes Rendering.

Ich stelle mir das so vor, das man nicht nur sagt was wo und wie gezeichnet werden soll, sondern das man ne Art Beschreibung wie der Fensterinhalt aussehen soll (ich denke da z.B. an Vektorgrafik) und das alles was mit Verschiebung und Größenänderung zu tun hat, kann der GUI-Server machen.
Das erledigt das Toolkit, wie z.B. Qt/GTK oder das wird mit Techniken wie XUL (XML User Interfaces) erschlagen, der GUI-Server sollte an sich kein Toolkit voraussetzen.

Oder würde das zu kompliziert, umständlich und langsamen werden?
Indirektes Rendering ist hardwarebeschleunigt nur möglich, wenn der GUI-Server gleichzeitig der Grafiktreiber ist (und somit alle Funktionen kennt), was Anwendungen damit an den GUI-Server bindet (also von der Grafikhardware abhängig ist) oder wenn jede Anfrage vom GUI-Server an die Grafikkarte geleitet wird, wenn er sie selbst nicht erfüllen kann (was Overhead ist).

Direktes Rendering ist gut.

Gruß,
Svenska

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #44 am: 25. November 2010, 10:18 »
Zitat von: svenska
Du zeichnest keine Bitmap und sendest die an den GUI-Server, sondern du zeichnest in einen Puffer, der dir vom GUI-Server zur Verfügung gestellt wurde und nutzt dazu Funktionen, die dir vom Grafiktreiber (DRI/DRM) zur Verfügung gestellt werden. Diese Funktionen sind im Prinzip ein OpenGL- (oder DirectX-)Kommandostrom, der von der Grafikkarte direkt verarbeitet wird.
Dieser Puffer liegt ja optimaler Weise im Graka RAM oder?

Wie funktioniert das eigentlich mit den beschleunigten Funktionen der Graka, kann man die für jede Art von RAM (Board oder Graka) nutzen oder sind die irgendwie beschränkt?

Zitat von: svenska
Insbesondere 3D-Spiele wollen ja die Grafikkarte ausreizen und müssen somit zwangsweise direkt mit dem Grafiktreiber sprechen.
Bzw. "sprechen" sie mit der OpenGL Implementierung des Treibers.

Mal ganz blöd zu OpenGL gefragt, kann ich mir das dann wir RPC vorstellen? Bzw. wimre dann haben die ganzen OpenGL (bzw. die meisten) Funktionen keinen Rückgabewert, da lohnt es sich ja dann so richtig, einfach nen RingBuffer zu nehmen und da die Daten an den OpenGL-Treiber zu schicken.

Was noch wichtig ist, sollte man komplett auf OpenGL setzen (also auch einfache Fenster-Sachen und sowas) oder sollte man ein paar grundlegende 2D Funktionen anbieten und dann halt wer will OpenGL?

Wenn ich alles mit OpenGL erschlage, dann ist es natürlich auch (sofern unterstützt) beschleunigt, aber ich habe natürlich auch nen ganz schönen Aufwand erstmal nen Treiber und die GUI zum Laufen zu bringen.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #45 am: 25. November 2010, 11:20 »
Zitat von: svenska
Du zeichnest keine Bitmap und sendest die an den GUI-Server, sondern du zeichnest in einen Puffer, der dir vom GUI-Server zur Verfügung gestellt wurde und nutzt dazu Funktionen, die dir vom Grafiktreiber (DRI/DRM) zur Verfügung gestellt werden. Diese Funktionen sind im Prinzip ein OpenGL- (oder DirectX-)Kommandostrom, der von der Grafikkarte direkt verarbeitet wird.
Dieser Puffer liegt ja optimaler Weise im Graka RAM oder?
Für Bitmaps ja, für OpenGL-Kommandoströme nein (die werden vom Grafiktreiber in hardwareabhängige Shadersprache umgesetzt).

Wie funktioniert das eigentlich mit den beschleunigten Funktionen der Graka, kann man die für jede Art von RAM (Board oder Graka) nutzen oder sind die irgendwie beschränkt?
Keine Ahnung. Hängt wahrscheinlich auch konkret von der Hardware ab (und ist damit Teil des Treibers). edit: PCI-Grafikkarten haben keinen Zugriff auf den RAM und die AGP Aperture Size ist auch immer begrenzt. Für Shared Memory-Grafik gibt es nur einen festen Bereich im RAM, der genutzt wird; wäre es egal, könnte der Treiber das festlegen. Also in der Allgemeinheit geht das nicht.

Umgekehrt kann man aber drüber nachdenken: Der Amiga hat verschiedene Arten von RAM mit verschiedenen Geschwindigkeiten und unterschiedlicher Adressierung. Linux auf dem Amiga nutzt nur den ChipRAM und stellt den restlichen Speicher (FastRAM, SlowRAM) als Blockdevice zur Verfügung. Dieses Blockdevice wird dann als Swapspace mit unterschiedlicher Priorität, je nach Zugriffsgeschwindigkeit, genutzt. Sowas könnte man natürlich auch mit dem Grafikspeicher auf modernen Grafikkarten machen, wenn man den Speicher dort eh nicht nutzt.

Zitat von: svenska
Insbesondere 3D-Spiele wollen ja die Grafikkarte ausreizen und müssen somit zwangsweise direkt mit dem Grafiktreiber sprechen.
Bzw. "sprechen" sie mit der OpenGL Implementierung des Treibers.
Richtig, die ist aber prinzipiell kartenabhängig wegen der ganzen Erweiterungen.

Mal ganz blöd zu OpenGL gefragt, kann ich mir das dann wir RPC vorstellen? Bzw. wimre dann haben die ganzen OpenGL (bzw. die meisten) Funktionen keinen Rückgabewert, da lohnt es sich ja dann so richtig, einfach nen RingBuffer zu nehmen und da die Daten an den OpenGL-Treiber zu schicken.

Was noch wichtig ist, sollte man komplett auf OpenGL setzen (also auch einfache Fenster-Sachen und sowas) oder sollte man ein paar grundlegende 2D Funktionen anbieten und dann halt wer will OpenGL?
Also wenn man sich Cairo, GTK oder Qt anschaut, dann sind das in erster Linie Toolkits für 2D. Diese sind aber so programmiert, dass sie verschiedene Backends nutzen, konkret gibt es da mindestens was für Xlib (indirekt/via Netzwerk), Xshm (indirekt/via shared memory), XRENDER (2D-beschleunigter X-Server) und GL (OpenGL).

Wenn ich alles mit OpenGL erschlage, dann ist es natürlich auch (sofern unterstützt) beschleunigt, aber ich habe natürlich auch nen ganz schönen Aufwand erstmal nen Treiber und die GUI zum Laufen zu bringen.
Du kannst das aber in einem Wrapper - eben dem Toolkit - machen. Das existiert bereits.

Mal abgesehen davon muss deine Hardware hinreichend schnell sein, damit du ohne großen Performanceverlust dein 2D über die 3D-Engine machen kannst. Das schließt sämtliche nicht-3D-fähige Hardware aus (da müsstest du 3D emulieren) und langsame/alte 3D-Karten (ATI Rage, NVidia TNT) sind in jedem Fall wesentlich langsamer im 3D-Modus als im 2D-Modus.

edit: Wenn du dir es einfach machen möchtest, ohne Grafiktreiberentwickler mit Ahnung zu engagieren, dann solltest du KMS/DRI/TTM und Freunde von Linux portieren und darauf die fertigen Gallium3D-Treiber aufsetzen. Das ist trotzdem eine Mordsarbeit. ;-) Ich würde mir den Stress mit 3D eher nicht machen.

Gruß,
Svenska
« Letzte Änderung: 25. November 2010, 11:30 von Svenska »

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #46 am: 25. November 2010, 11:32 »
Zitat von: svenska
Für Bitmaps ja, für OpenGL-Kommandoströme nein (die werden vom Grafiktreiber in hardwareabhängige Shadersprache umgesetzt).
Genau hier habe ich jetzt so meine Verständnisprobleme. Ansich zeichnen die OpenGL Befehle doch auch nur in eine Bitmap rein oder?

Denn ich frage mich gerade wie es sonst möglich ist, das jede Anwendung die Hardwarebeschleunigten Funktionen zu nutzen, ohne das die Graka weiß in welcher Reihenfolge die Fenster gezeichnet werden oder welche Fenster sich wo überlappen?

Zitat von: svenska
Mal abgesehen davon muss deine Hardware hinreichend schnell sein, damit du ohne großen Performanceverlust dein 2D über die 3D-Engine machen kannst. Das schließt sämtliche nicht-3D-fähige Hardware aus (da müsstest du 3D emulieren) und langsame/alte 3D-Karten (ATI Rage, NVidia TNT) sind in jedem Fall wesentlich langsamer im 3D-Modus als im 2D-Modus.
Also wird wohl, vorallem in meinem Fall (älter Hardware >= P75), eine Unterteilung in einen 2D- und einen 3D-Treiber besser sein. Zumal es so auch einfacher wird, denn ich denke mal einen 2D-Treiber (z.B. Vesa) hat mal wesentlich schneller "geschrieben" als nen 3D-Treiber und somit könnte man dann einfach den Treiber regeln lassen, ob die Graka schnell genug ist, das alles im 3D-Modus gerendert werden kann.

Was ich mir auch noch nicht so richtig vorstellen kann, wie funktioniert das eigentlich wenn man mehrere Grakas und mehrere Bildschirme oder eine Graka für 2D und eine für 3D (z.B. alte Voodoo) hat?

Denn so wie ich mir das denke, muss man erstmal alle RPC Anfragen an den GUI-Server schicken und der schickt die dann weiter an den entsprechenden Treiber (zwecks anderer Bildschirm oder zur Unterscheidung 2D/3D).

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #47 am: 25. November 2010, 16:11 »
Zitat von: svenska
Für Bitmaps ja, für OpenGL-Kommandoströme nein (die werden vom Grafiktreiber in hardwareabhängige Shadersprache umgesetzt).
Genau hier habe ich jetzt so meine Verständnisprobleme. Ansich zeichnen die OpenGL Befehle doch auch nur in eine Bitmap rein oder?
Nein. Die OpenGL-Befehle zeichnen nicht, sondern sie Steuern den Ablauf der Grafikkarte. Am Ende taucht etwas in einem Puffer auf.

Denn ich frage mich gerade wie es sonst möglich ist, das jede Anwendung die Hardwarebeschleunigten Funktionen zu nutzen, ohne das die Graka weiß in welcher Reihenfolge die Fenster gezeichnet werden oder welche Fenster sich wo überlappen?
Du hast zwei Ebenen... einmal zeichnet jede Anwendung in einen Puffer. Die Fensterverwaltung weiß nun, welche Puffer zu irgendwelchen Fenstern gehören, wie die sich überlappen und erzeugt dann Bereiche auf dem Bildschirm (z.B. Rechtecke), die dann mit den nicht-überlappenden Puffern hinterlegt werden.

Also wird wohl, vorallem in meinem Fall (älter Hardware >= P75), eine Unterteilung in einen 2D- und einen 3D-Treiber besser sein. Zumal es so auch einfacher wird, denn ich denke mal einen 2D-Treiber (z.B. Vesa) hat mal wesentlich schneller "geschrieben" als nen 3D-Treiber und somit könnte man dann einfach den Treiber regeln lassen, ob die Graka schnell genug ist, das alles im 3D-Modus gerendert werden kann.
Ich behaupte, dass aus dem Forum maximal eine Handvoll Personen in der Lage sind, einen gebrauchbaren 3D-Treiber für eine real existierende Grafikkarte zu schreiben.

Was ich mir auch noch nicht so richtig vorstellen kann, wie funktioniert das eigentlich wenn man mehrere Grakas und mehrere Bildschirme oder eine Graka für 2D und eine für 3D (z.B. alte Voodoo) hat?
Die reinen 3D-Karten zeichnen nicht in einen Puffer, sondern direkt in das VGA-Signal. Wo hingezeichnet werden soll, entscheidet der Treiber - und der bekommt von der Fensterverwaltung die Informationen zu Position und Überlappungszustand des entsprechenden Fensters. Wobei solche Geräte fast nicht mehr existieren.

Anwendungen brauchen für 3D-Darstellung einen Puffer. Dieser Puffer wird einer Grafikkarte zugeordnet. Wenn das Fenster, was den Pufferinhalt darstellen soll, auf einer anderen Grafikkarte angezeigt werden soll, dann musst du das Rendering-Ergebnis in jedem Frame von einem Grafikspeicher in einen anderen Grafikspeicher kopieren. Oder du kannst diesen Puffer von einer Grafikkarte auf eine andere "umziehen" (das ist Voraussetzung für dynamisch abschaltbare Grafikkarten, wie Intel&NVidia in Notebooks) - das setzt aber voraus, dass die Anwendung darüber informiert werden und zustimmen muss. Schließlich darf die Anwendung ja hardwareabhängige (OpenGL-)Befehle ausführen, die es auf der anderen Karte nicht gibt.

Denn so wie ich mir das denke, muss man erstmal alle RPC Anfragen an den GUI-Server schicken und der schickt die dann weiter an den entsprechenden Treiber (zwecks anderer Bildschirm oder zur Unterscheidung 2D/3D).

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #48 am: 25. November 2010, 16:46 »
Zitat von: svenska
Du hast zwei Ebenen... einmal zeichnet jede Anwendung in einen Puffer. Die Fensterverwaltung weiß nun, welche Puffer zu irgendwelchen Fenstern gehören, wie die sich überlappen und erzeugt dann Bereiche auf dem Bildschirm (z.B. Rechtecke), die dann mit den nicht-überlappenden Puffern hinterlegt werden.
So weit mein vorhanden Wissen richtig ist, gibt es die Möglichkeit normalen RAM für die Graka zu nutzen erst seit AGP oder?

Denn es stellt sich mir schon die Frage, was passiert wenn man so viele Fenster offen hat das die nicht mehr alle in den Graka RAM passen oder als anderes Bsp. was ist mit den ganzen Tabs die man in einem Webbrowser offen haben kann, im Prinzip sind das doch eigenständige Fenster oder?

Zitat von: svenska
Ich behaupte, dass aus dem Forum maximal eine Handvoll Personen in der Lage sind, einen gebrauchbaren 3D-Treiber für eine real existierende Grafikkarte zu schreiben.
Ich denke mal es ist nicht mal so schwer nen 3D-Treiber zu schreiben, aber die Dokumentation (die nicht vorhanden ist) macht es einem ja unmöglich.

Zitat von: svenska
Anwendungen brauchen für 3D-Darstellung einen Puffer. Dieser Puffer wird einer Grafikkarte zugeordnet. Wenn das Fenster, was den Pufferinhalt darstellen soll, auf einer anderen Grafikkarte angezeigt werden soll, dann musst du das Rendering-Ergebnis in jedem Frame von einem Grafikspeicher in einen anderen Grafikspeicher kopieren. Oder du kannst diesen Puffer von einer Grafikkarte auf eine andere "umziehen" (das ist Voraussetzung für dynamisch abschaltbare Grafikkarten, wie Intel&NVidia in Notebooks) - das setzt aber voraus, dass die Anwendung darüber informiert werden und zustimmen muss. Schließlich darf die Anwendung ja hardwareabhängige (OpenGL-)Befehle ausführen, die es auf der anderen Karte nicht gibt.
Das die Anwendung informiert werden muss gilt doch aber nur für 3D-Anwendungen oder?

Ich selbst habe kein Multi-Monitoring, aber wenn ich an einer Graka mehrere Monitore angeschlossen habe, dann läuft alles über den Treiber, welcher Teil vom Fenster auf welchem Monitor dargestellt wird oder?
Interessant wird es erst, wenn man mehrere Grakas und dort jeweils nen Monitor dran hat. Der Einfachheit halber würde ich sagen, das ein Fenster nicht teilweise auf 2 Monitoren gleichzeitg (und damit auf 2 Grakas gleichzeit) sein kann, aber könnte man das machen?
Bei so einem Fall wäre es dann auch besser, wenn man die Befehle grundsätzliche erstmal zum GUI-Server sendet und der die dann an die entsprechende Graka weitersendet. Für den normalen Fall, das nur eine Graka vorhanden ist (was ja auf modernen Notebooks auch nicht mehr zutrifft) kann man ja einfach diesen Schritt weglassen und die Daten werden gleich zum Treiber gesendet.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #49 am: 25. November 2010, 17:41 »
Zitat von: svenska
Du hast zwei Ebenen... einmal zeichnet jede Anwendung in einen Puffer. Die Fensterverwaltung weiß nun, welche Puffer zu irgendwelchen Fenstern gehören, wie die sich überlappen und erzeugt dann Bereiche auf dem Bildschirm (z.B. Rechtecke), die dann mit den nicht-überlappenden Puffern hinterlegt werden.
So weit mein vorhanden Wissen richtig ist, gibt es die Möglichkeit normalen RAM für die Graka zu nutzen erst seit AGP oder?
Ja, aber auch da nicht universell, sondern (soweit ich weiß) nur für Texturen.

Denn es stellt sich mir schon die Frage, was passiert wenn man so viele Fenster offen hat das die nicht mehr alle in den Graka RAM passen oder als anderes Bsp. was ist mit den ganzen Tabs die man in einem Webbrowser offen haben kann, im Prinzip sind das doch eigenständige Fenster oder?
Naja, deine Bildschirmauflösung sind z.B. 1920x1080x4 ergibt etwa 8 MB. Dinge, die gerendert, aber nicht angezeigt werden, brauchen im Grafikspeicher nicht vorliegen. Jedes Mal, wenn du ein Fenster in den Vordergrund holst oder von außen auf den Bildschirm zurückschiebst, wird vom GUI-Server ein Ereignis "Please Repaint" an das Fenster geschickt. Das ist Voraussetzung. Wenn du Bildschirminhalte cachen möchtest, dann tust du das und sparst dir diese Ereignisse. Ist der Grafikspeicher voll, werden nicht angezeigte Inhalte halt verworfen.

Zitat von: svenska
Ich behaupte, dass aus dem Forum maximal eine Handvoll Personen in der Lage sind, einen gebrauchbaren 3D-Treiber für eine real existierende Grafikkarte zu schreiben.
Ich denke mal es ist nicht mal so schwer nen 3D-Treiber zu schreiben, aber die Dokumentation (die nicht vorhanden ist) macht es einem ja unmöglich.
Seh ich anders, allein schon die Diskussionen um die Implementierung der vielen OpenGL-Erweiterungen usw. zeigen mir das. Die Doku ist nur noch ein "layer of problems".

Das die Anwendung informiert werden muss gilt doch aber nur für 3D-Anwendungen oder?
Würde ich auch für 2D machen. Schließlich kannst du die 2D-Beschleunigung ähnlich implementieren. ;-) Im engeren Sinne hast du aber Recht (GUI-Server macht 2D, für 3D gibt es einen Durchgriff in die Hardware/den Treiber).

Ich selbst habe kein Multi-Monitoring, aber wenn ich an einer Graka mehrere Monitore angeschlossen habe, dann läuft alles über den Treiber, welcher Teil vom Fenster auf welchem Monitor dargestellt wird oder?
Jain. Sinnvoll ist es, den Bildschirm zu abstrahieren. Eine Grafikhardware stellt dir dann einen (oder mehrere) Bildschirme zur Verfügung; jeder Bildschirm gehört genau einer Grafikkarte.

Interessant wird es erst, wenn man mehrere Grakas und dort jeweils nen Monitor dran hat. Der Einfachheit halber würde ich sagen, das ein Fenster nicht teilweise auf 2 Monitoren gleichzeitg (und damit auf 2 Grakas gleichzeit) sein kann, aber könnte man das machen?
Kann man, ist aber nicht unbedingt sinnvoll. Wenn du ein Video (beschleunigt) oder ein 3D-Inhaltsfenster über zwei Monitore verteilst, hängt es von der Kombination ab, auf welchem Bildschirm Inhalt auftaucht und auf welchem Bildschirm nur schwarz angezeigt wird.

Ich habe bei einem Kumpel unter Windows XP eine S3 Trio64 zusätzlich zu einer ATI Radeon installiert. Wenn du einen VLC vollständig(!) auf die S3 verschiebst (also nicht dort öffnest), stürzt er ab. Bei 3D-Spielen genauso. Schiebst du das Fenster zwischen den beiden Monitoren der Radeon hin und her, so wird das Video auf beiden dargestellt, aber das 3D-Spiel ist auf dem Bildschirm schwarz, der nicht die obere linke Ecke des Spiels besitzt. ;-)

Bei so einem Fall wäre es dann auch besser, wenn man die Befehle grundsätzliche erstmal zum GUI-Server sendet und der die dann an die entsprechende Graka weitersendet. Für den normalen Fall, das nur eine Graka vorhanden ist (was ja auf modernen Notebooks auch nicht mehr zutrifft) kann man ja einfach diesen Schritt weglassen und die Daten werden gleich zum Treiber gesendet.
Du bindest einfach ein Fenster an einen Bildschirm. Verlässt das Fenster teilweise den Bildschirm, so ist es "draußen". Erst, wenn das Fenster vollständig auf einem anderen Bildschirm ist, musst du die Datenstrukturen umziehen.

Da kann man noch viel überlegen und überdenken.

Gruß,
Svenska

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #50 am: 25. November 2010, 19:13 »
Zitat von: svenska
Jain. Sinnvoll ist es, den Bildschirm zu abstrahieren. Eine Grafikhardware stellt dir dann einen (oder mehrere) Bildschirme zur Verfügung; jeder Bildschirm gehört genau einer Grafikkarte.
Jein, würde ich etwas anders machen. Jeder Desktop darf nur auf einer Graka sein, über wieviele Bildschirme sich der Desktop dann erstreckt ist Sache des Treibers/der Graka.

Zitat von: svenska
Du bindest einfach ein Fenster an einen Bildschirm. Verlässt das Fenster teilweise den Bildschirm, so ist es "draußen". Erst, wenn das Fenster vollständig auf einem anderen Bildschirm ist, musst du die Datenstrukturen umziehen.
Wie gesagt, würde ich das pro Desktop machen, aber ansonsten macht man halt die Vereinfachung das ein Fenster nur komplett auf einem Desktop sein kann und nicht teilweise auf mehreren.

Ich bezog mich aber darauf, das du auch die jeweilige Graka in den Puffer schreiben lässt und nicht alles eine Graka machen lässt.

Was mich auch dazu bringt, das entweder alle Puffer der Fenster im Graka RAM sein müssen oder die Graka in den gesamten RAM schreiben kann.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #51 am: 25. November 2010, 21:48 »
Zitat von: svenska
Jain. Sinnvoll ist es, den Bildschirm zu abstrahieren. Eine Grafikhardware stellt dir dann einen (oder mehrere) Bildschirme zur Verfügung; jeder Bildschirm gehört genau einer Grafikkarte.
Jein, würde ich etwas anders machen. Jeder Desktop darf nur auf einer Graka sein, über wieviele Bildschirme sich der Desktop dann erstreckt ist Sache des Treibers/der Graka.
Definiere "Desktop". Meinst du das Root-Window? Das ist ein Fenster wie jedes andere und erstreckt sich vollständig über einen Bildschirm (im Sinne meiner Abstraktion). Du hast also für jeden Bildschirm ein eigenes Root-Window.

Zitat von: svenska
Du bindest einfach ein Fenster an einen Bildschirm. Verlässt das Fenster teilweise den Bildschirm, so ist es "draußen". Erst, wenn das Fenster vollständig auf einem anderen Bildschirm ist, musst du die Datenstrukturen umziehen.
Wie gesagt, würde ich das pro Desktop machen, aber ansonsten macht man halt die Vereinfachung das ein Fenster nur komplett auf einem Desktop sein kann und nicht teilweise auf mehreren.
Richtig. Du kannst ja das Fenster selbst auf mehreren Desktops anzeigen lassen, das Rendering (der Inhalt) geschieht aber nur auf dem Bildschirm, der das Fenster "besitzt". Ein 2D-Fenster umzuziehen ist kein Problem (du schickst der Anwendung ein Repaint-Event), bei 3D wird das schwieriger, weil du dort Zustände hast, die mit umziehen müssten. Dort kann man das aber auch komplett verbieten (oder durch Kopieren/Frame langsam aber möglich machen).

Ich bezog mich aber darauf, das du auch die jeweilige Graka in den Puffer schreiben lässt und nicht alles eine Graka machen lässt.

Was mich auch dazu bringt, das entweder alle Puffer der Fenster im Graka RAM sein müssen oder die Graka in den gesamten RAM schreiben kann.
Eine Graka kann nicht in den gesamten RAM schreiben, weil sie keinen Zugriff hat (insbesondere nicht auf den Grafikspeicher einer anderen Grafikkarte.

Du ordnest jedem Fenster einen Puffer zu, in den der Fensterinhalt gerendert wird. Zusätzlich besitzt jeder Puffer eine Grafikkarte, der er zugeordnet ist. Damit hast du indirekt alle Fenster einer Grafikkarte (und damit allen Bildschirmen, die an dieser Grafikkarte hängen!) zugeordnet. Das Umziehen im 2D ist kein Problem.

Es gibt aber bei der ganzen Diskussion einen Punkt zu beachten... und zwar die Initialisierung. Du kannst zwar mit VGA/VESA einen einfachen Grafiktreiber bauen, aber der funktioniert über den int 10h. Um Multimonitoring zu ermöglichen, musst du die Grafikkarten aber selbst ohne Hilfe des BIOS initialisieren und das ist recht kompliziert. Das führt z.B. auch dazu, dass in meinem Testfall die S3 Trio64 nur funktioniert, wenn sie im BIOS als primäre Grafikkarte eingetragen ist - der Windows-Bootscreen und BIOS-Meldungen tauchen nur auf dem dritten Bildschirm auf. Der Windows-Treiber für S3-Grafikkarten macht die Initialisierung jedenfalls nur über das Video-BIOS. Es gibt auch Grafikkarten die dies erfordern (ich habe eine S3 Trio32, die im BIOS primär sein muss, sonst hängt sich das BIOS direkt ohne Ausgabe weg!). In jedem Fall brauchst du einen direkt zugeschnittenen Hardwaretreiber, um soetwas zu ermöglichen.

Von daher kann man sich zwar ein paar Gedanken machen, aber die Implementierung ist weit, weit weg. ;-) Für ein Hobby-OS sinnvoll ist ein VESA-Treiber und eine darauf basierende 2D-Oberfläche; wenn man weiter ist, sind BitBlt und Videobeschleunigung (YUV -> RGB geht ab S3 Savage und ähnlich) noch wichtig.

Gruß,
Svenska

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #52 am: 25. November 2010, 22:04 »
Zitat von: svenska
Definiere "Desktop". Meinst du das Root-Window? Das ist ein Fenster wie jedes andere und erstreckt sich vollständig über einen Bildschirm (im Sinne meiner Abstraktion). Du hast also für jeden Bildschirm ein eigenes Root-Window.
Definiere "Root-Window" ;)

Mit Desktop meine ich einen Desktop wie du ihn unter Windows kennst. Unter KDE und Konsorten ist es üblich mehrere virtuelle Desktops zu haben. Ich will darauf hinaus, das der Treiber ja einen großen Desktop dem System gegenüber anbieten kann, dieser wird aber z.B. auf 3 Monitore verteilt dargestellt, ohne das sich außer dem Treiber jemand darüber Gedanken machen muss.

Zitat von: svenska
Eine Graka kann nicht in den gesamten RAM schreiben, weil sie keinen Zugriff hat (insbesondere nicht auf den Grafikspeicher einer anderen Grafikkarte.
Deswegen meine Idee das die Daten erst an den GUI-Server geschickt werden und der ne Art Vermittler ist und die Daten an den richtigen Treiber weitersendet.

Zitat von: svenska
Du ordnest jedem Fenster einen Puffer zu, in den der Fensterinhalt gerendert wird. Zusätzlich besitzt jeder Puffer eine Grafikkarte, der er zugeordnet ist. Damit hast du indirekt alle Fenster einer Grafikkarte (und damit allen Bildschirmen, die an dieser Grafikkarte hängen!) zugeordnet. Das Umziehen im 2D ist kein Problem.
Ist ja alles richtig, aber wie du weiter oben schon sagtest kann eine Graka nicht auf den gesamten RAM zugreifen. Meine Frage ist dann halt, was macht man wenn der RAM auf den die Graka zugreifen kann voll ist?

Eine Lösung wäre das der Puffer vom Fenster in den Graka RAM kopiert wird, dort wird dann "gezeichnet" und dann kopierst du den Puffer wieder zurück in den normalen RAM. Der GUI-Server erstellt dann den fertigen Frame und kopiert das wieder in den Graka RAM.
Diese Variante ist aber verdammt langsam. Gibt es denn noch eine andere Möglichkeit?

Zitat von: svenska
Von daher kann man sich zwar ein paar Gedanken machen, aber die Implementierung ist weit, weit weg. wink Für ein Hobby-OS sinnvoll ist ein VESA-Treiber und eine darauf basierende 2D-Oberfläche; wenn man weiter ist, sind BitBlt und Videobeschleunigung (YUV -> RGB geht ab S3 Savage und ähnlich) noch wichtig.
Ich wollte meine Interfaces was das betrifft so flexibel wie möglich halten, vielleicht will ich ja irgendwann mal mit solchen Sachen rumspielen und da will ich nicht alles neuschreiben müssen.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #53 am: 25. November 2010, 22:24 »
Zitat von: svenska
Definiere "Desktop". Meinst du das Root-Window? Das ist ein Fenster wie jedes andere und erstreckt sich vollständig über einen Bildschirm (im Sinne meiner Abstraktion). Du hast also für jeden Bildschirm ein eigenes Root-Window.
Definiere "Root-Window" ;)
Das war der X11-Sinn. Es handelt sich um das einzige Fenster (auf einem X11-Screen), welches kein "parent window" hat, was die Position (0|0) und die maximale Größe des Screens hat.

Wenn man allerdings mit Xinerama und XRandR betrachtet, ist das Root-Window das Fenster, welches über alle Bildschirme geht, also bei 3 1024x768-Bildschirmen nebeneinander 3072x768 groß ist und oben links auf dem linken Bildschirm beginnt. ;-)

Mit Desktop meine ich einen Desktop wie du ihn unter Windows kennst. Unter KDE und Konsorten ist es üblich mehrere virtuelle Desktops zu haben. Ich will darauf hinaus, das der Treiber ja einen großen Desktop dem System gegenüber anbieten kann, dieser wird aber z.B. auf 3 Monitore verteilt dargestellt, ohne das sich außer dem Treiber jemand darüber Gedanken machen muss.
Das ist das Xinerama-Prinzip. Dein Desktop ist somit das Root-Window und alle Fenster sind Kinder dieses Fensters (und können auch nur innerhalb dessen Abmessungen liegen).

Zitat von: svenska
Eine Graka kann nicht in den gesamten RAM schreiben, weil sie keinen Zugriff hat (insbesondere nicht auf den Grafikspeicher einer anderen Grafikkarte.
Deswegen meine Idee das die Daten erst an den GUI-Server geschickt werden und der ne Art Vermittler ist und die Daten an den richtigen Treiber weitersendet.
Ja, das wäre aber wieder indirektes Rendering. Wenn dein Treiber Multimonitoring kann, dann ist 3D-Fähigkeit nicht weit (es gibt kaum Grafikkarten mit mehreren Heads, aber ohne 3D-Hardware) und um das sinnvoll zu ermöglichen, braucht man direktes Rendering.

Zitat von: svenska
Du ordnest jedem Fenster einen Puffer zu, in den der Fensterinhalt gerendert wird. Zusätzlich besitzt jeder Puffer eine Grafikkarte, der er zugeordnet ist. Damit hast du indirekt alle Fenster einer Grafikkarte (und damit allen Bildschirmen, die an dieser Grafikkarte hängen!) zugeordnet. Das Umziehen im 2D ist kein Problem.
Ist ja alles richtig, aber wie du weiter oben schon sagtest kann eine Graka nicht auf den gesamten RAM zugreifen. Meine Frage ist dann halt, was macht man wenn der RAM auf den die Graka zugreifen kann voll ist?
Für 2D-Anwendungen wirfst du einfach alles nicht dargestellte weg. Ein FullHD-Schirm belegt 8 MB, alles weitere brauchst du nicht cachen. Die Anwendung muss neuzeichnen, wenn du ein Fenster in den Vordergrund bringst.

Bei 3D-Anwendungen ist das komplizierter, allerdings haben Spiele immer eine Mindestanforderung an den Grafikspeicher, weil man bei einem bestimmten Verbrauch halt keine Texturen o.ä. hochladen kann und das ist für Spiele schädlich. "Grafikspeicher voll" ist eine Bedingung, die ich nicht als Problem sehe. Zumal 2D-Anwendungen fast keinen brauchen.

Eine Lösung wäre das der Puffer vom Fenster in den Graka RAM kopiert wird, dort wird dann "gezeichnet" und dann kopierst du den Puffer wieder zurück in den normalen RAM. Der GUI-Server erstellt dann den fertigen Frame und kopiert das wieder in den Graka RAM.
Diese Variante ist aber verdammt langsam. Gibt es denn noch eine andere Möglichkeit?
Also Double Buffering (der gesamte dargestellte Bildschirminhalt) ist eine Möglichkeit, den VESA-Treiber enorm zu beschleunigen. Wenn du nämlich die MTRRs entsprechend gesetzt hast, ist ein Bulk-Upload der 8 MB Framebuffer wesentlich schneller, als viele Zugriffe (z.B. jedes Pixel) auf den Grafikspeicher einzeln durchzuführen.

Du hast definitiv genug Platz im Grafikspeicher, um den aktuellen Bildschirminhalt anzuzeigen (der wird vom CRTC ausgelesen, muss also im GrafikRAM liegen). Im Zweifelsfall kannst du immer direkt auf diesem Bereich arbeiten, um die gerenderten Fenster darzustellen. Der Puffer, den du der Anwendung bereitstellst, kann ja direkt im Framebuffer liegen. Allerdings verlierst du damit die Möglichkeit des VSync (führt zu tearing).

Ich wollte meine Interfaces was das betrifft so flexibel wie möglich halten, vielleicht will ich ja irgendwann mal mit solchen Sachen rumspielen und da will ich nicht alles neuschreiben müssen.
X11 war auch nie mit 3D im Gedanken entwickelt worden. Wenn du das wirklich implementieren möchtest, dann schau dir mal Wayland an, zumindest die Konzepte.

Für ein Hobby-OS halte ich gebrauchbare 3D-Beschleunigung jedenfalls für unrealistisch. Dazu ist die Hardware definitiv zu kompliziert (und für NVidia oder VIA auch viel zu schlecht dokumentiert).

Gruß,
Svenska

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #54 am: 26. November 2010, 10:06 »
Zitat von: svenska
Ja, das wäre aber wieder indirektes Rendering. Wenn dein Treiber Multimonitoring kann, dann ist 3D-Fähigkeit nicht weit (es gibt kaum Grafikkarten mit mehreren Heads, aber ohne 3D-Hardware) und um das sinnvoll zu ermöglichen, braucht man direktes Rendering.
Ich meine das anders, stell dir den GUI-Server in dem Moment vor wir nen Switch, der GUI-Server guckt sich nicht den Inhalt der Daten an, sondern er leitet sie einfach nur an den richtigen Treiber weiter.

Zitat von: svenska
Also Double Buffering (der gesamte dargestellte Bildschirminhalt) ist eine Möglichkeit, den VESA-Treiber enorm zu beschleunigen. Wenn du nämlich die MTRRs entsprechend gesetzt hast, ist ein Bulk-Upload der 8 MB Framebuffer wesentlich schneller, als viele Zugriffe (z.B. jedes Pixel) auf den Grafikspeicher einzeln durchzuführen.
Sprich für den VESA-Treiber, der sowieso keine Hardwarebeschleunigung hat, lohnt es sich, einen Frame erst im normalen RAM zusammenzustellen und ihn dann mit einmal in den Framebuffer zu kopieren?

Wenn ich dann nen Treiber habe für ne einfache Graka, die nicht alzu viel Speicher hat, würde ich das dann so machen, das ich 2 Puffer im RAM habe, jeweils ein Frame und immer in den Puffer zeichnen lasse der nicht gerade angezeigt wird (ist bestimmt auch die gängige Methode für DoubleBuffering oder?).

Zitat von: svenska
Für ein Hobby-OS halte ich gebrauchbare 3D-Beschleunigung jedenfalls für unrealistisch. Dazu ist die Hardware definitiv zu kompliziert (und für NVidia oder VIA auch viel zu schlecht dokumentiert).
Ich muss mit mal Gallium3D angucken, vllt lohnt es sich das zu portieren. Ansonsten ist so ein 3D-Treiber natürlich eine schöne Beschäftigung wenn man zu viel Zeit hat ;)

Edit::

Die Frage die sich mir stellt ist, warum wird eigentlich nicht jedes Fenster im Graka RAM (so fern genug verfügbar) gespeichert und wenn ein neuer Frame erstellt wird, wird einfach aus diesem Puffer gelesen? Ich meine dass das Neuzeichnen in dem Fall wegfällt und es wird nur neugezeichnet, wenn sich etwas im Fensterinhalt geändert hat.
Der einzige Grund der mir spontan einfällt das nicht zu machen ist, dass es "billiger" ist nur neuzuzeichnen, wenn das Fenster oder ein Teil davon zu sehen ist und ansonsten wird das Zeichnen einfach nicht gemacht.
« Letzte Änderung: 26. November 2010, 10:16 von FlashBurn »

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #55 am: 26. November 2010, 14:11 »
Zitat von: svenska
Ja, das wäre aber wieder indirektes Rendering. Wenn dein Treiber Multimonitoring kann, dann ist 3D-Fähigkeit nicht weit (es gibt kaum Grafikkarten mit mehreren Heads, aber ohne 3D-Hardware) und um das sinnvoll zu ermöglichen, braucht man direktes Rendering.
Ich meine das anders, stell dir den GUI-Server in dem Moment vor wir nen Switch, der GUI-Server guckt sich nicht den Inhalt der Daten an, sondern er leitet sie einfach nur an den richtigen Treiber weiter.
Achso. Naja, wenn du für jedes Fenster eh einen eigenen Puffer brauchst, kannst du die Puffer direkt den Treibern zuordnen. Damit rendert eine Anwendung in "ihren" Puffer und redet somit direkt mit dem Treiber. Der GUI-Server ist nur für das Erzeugen und Zuordnen der Puffer zuständig. ;-)

Zitat von: svenska
Also Double Buffering (der gesamte dargestellte Bildschirminhalt) ist eine Möglichkeit, den VESA-Treiber enorm zu beschleunigen. Wenn du nämlich die MTRRs entsprechend gesetzt hast, ist ein Bulk-Upload der 8 MB Framebuffer wesentlich schneller, als viele Zugriffe (z.B. jedes Pixel) auf den Grafikspeicher einzeln durchzuführen.
Sprich für den VESA-Treiber, der sowieso keine Hardwarebeschleunigung hat, lohnt es sich, einen Frame erst im normalen RAM zusammenzustellen und ihn dann mit einmal in den Framebuffer zu kopieren?
Ja.

Wenn ich dann nen Treiber habe für ne einfache Graka, die nicht alzu viel Speicher hat, würde ich das dann so machen, das ich 2 Puffer im RAM habe, jeweils ein Frame und immer in den Puffer zeichnen lasse der nicht gerade angezeigt wird (ist bestimmt auch die gängige Methode für DoubleBuffering oder?).
Genau so. Das ist übrigens nicht abhängig vom Speicher, den die Grafikkarte hat, sondern von dem Speicher, der in der Grafikkarte genutzt ist, also für VESA oder unbeschleunigte Treiber exakt Höhe*Breite*Farbtiefe.

Ich muss mit mal Gallium3D angucken, vllt lohnt es sich das zu portieren. Ansonsten ist so ein 3D-Treiber natürlich eine schöne Beschäftigung wenn man zu viel Zeit hat ;)
Richtig. Wobei ein Gallium3D-Treiber höchstwahrscheinlich POSIX voraussetzt (wahrscheinlich implizit), du also eine solche Umgebung für den Treiber brauchst.

Die Frage die sich mir stellt ist, warum wird eigentlich nicht jedes Fenster im Graka RAM (so fern genug verfügbar) gespeichert und wenn ein neuer Frame erstellt wird, wird einfach aus diesem Puffer gelesen? Ich meine dass das Neuzeichnen in dem Fall wegfällt und es wird nur neugezeichnet, wenn sich etwas im Fensterinhalt geändert hat.
Frühe Grafikkarten waren dumme Framebuffer (z.B. ISA-Karten mit 256-512 KB) mit wenig Speicher, da passt dann exakt ein Frame rein. Inzwischen kannst du den Fensterinhalt cachen (d.h. du speicherst den Fensterinhalt im RAM), das erspart dir das Neuzeichnen, wenn du ein Fenster in den sichtbaren Bereich verschiebst oder in den Vordergrund holst. Das Fenster direkt im Grafikspeicher zu speichern ist möglich, aber nicht unbedingt schnell (man denke an VESA 1.x, wo der Grafikspeicher nicht linear im Adressraum liegt!), außerdem ist der Lesezugriff auf Grafikspeicher wesentlich langsamer, als auf Systemspeicher - Grafikspeicher ist normalerweise langsamer getaktet, evtl. zeitweise gesperrt (während das CRTC gerade drin liest) und liegt nur über ein vergleichsweise langsames Interface, wie z.B. ISA oder PCI an.

Wenn du von einer modernen Grafikkarte mit AGP-/PCIe-Anbindung ausgehst, ist der Unterschied nicht mehr so beträchtlich, aber dann brauchst du (eigentlich) auch einen eigenen Treiber, damit das schnell ist.

Der einzige Grund der mir spontan einfällt das nicht zu machen ist, dass es "billiger" ist nur neuzuzeichnen, wenn das Fenster oder ein Teil davon zu sehen ist und ansonsten wird das Zeichnen einfach nicht gemacht.
Du kannst auf den Grafikspeicher nur indirekt (VESA 1.x) oder langsam (VESA 2.0/3.0) zugreifen. Den Effekt siehst du, wenn du mit dem VESA-Treiber für X11 oder Windows (kein Grafiktreiber) arbeitest und dann Fenster mitsamt Inhalt verschiebst. Das dauert und nervt. Im RAM geht das sehr schnell und die Daten dann in wenigen Zugriffen in die Grafikkarte stopfen ist schneller, als das in vielen kleinen Zugriffen zu machen.

Mit der Redraw-Logik, also welche Teile neu gezeichnet werden müssen, hat das nichts zu tun. Das erledigt auch nicht der GUI-Server. Die Anwendung bekommt ein Ereignis, welches nicht nur besagt "zeichne neu", sondern auch exakt die Bereiche angibt, welche neu gezeichnet werden müssen - das muss nicht das gesamte Fenster sein. Es gibt schließlich auch Anwendungen, die nicht neuzeichnen können (weil sie ihren Fensterinhalt nicht cachen) und einfach Teile des Inhalts (z.B. Graphen, Text, Benutzeroberfläche) neu berechnen und dann darstellen.

Gruß,
Svenska

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #56 am: 26. November 2010, 14:32 »
Zitat von: svenska
Achso. Naja, wenn du für jedes Fenster eh einen eigenen Puffer brauchst, kannst du die Puffer direkt den Treibern zuordnen. Damit rendert eine Anwendung in "ihren" Puffer und redet somit direkt mit dem Treiber. Der GUI-Server ist nur für das Erzeugen und Zuordnen der Puffer zuständig.
Wir waren uns ja einig, das die Graka nur in ihrem eigenen Speicher schreiben kann (Hardwarebeschleunigung) und da wäre es dann besser, wenn der GUI-Server sich um den ganzen Kram kümmert auf welchem Treiber das Fenster gerade läuft und das sollte auch den Umzug eines Fenster von einem Desktop zu einem anderen erleichtern.

Also wenn Hardwarebeschleunigung vorhanden ist, werde ich höchstwahrscheinlich auch genug Graka RAM haben um DoubleBuffering im Graka RAM zu machen und das würde heißen das jedes Mal neugezeichnet werden muss für ein Frame.
Ist die Graka so alt (oder ich habe keinen Treiber -> VESA), das ich nur nen Framebuffer habe, dann mache ich DoubleBuffering im RAM, aber es wird trotzdem für jedes Frame neugezeichnet.

Bei dieser Methode wäre doch aber eine sehr hohe CPU Belastung vorhanden, wegen dem ständigen Neuzeichnen oder?
Irgendwie muss man ja noch den Fall abfangen, das sich gar nichts geändert hat.

Zitat von: svenska
Richtig. Wobei ein Gallium3D-Treiber höchstwahrscheinlich POSIX voraussetzt (wahrscheinlich implizit), du also eine solche Umgebung für den Treiber brauchst.
Ich spiele immerhin schon mit dem Gedanken, meinem Kernel noch nen fork() hinzuzufügen (exec() brauche ich ja nicht explizit, dafür habe ich nen createTask()) und damit sollte ja die größte Hürde für POSIX genommen sein und eventuell kann man auch einiges anpassen.

Zitat von: svenska
Mit der Redraw-Logik, also welche Teile neu gezeichnet werden müssen, hat das nichts zu tun. Das erledigt auch nicht der GUI-Server. Die Anwendung bekommt ein Ereignis, welches nicht nur besagt "zeichne neu", sondern auch exakt die Bereiche angibt, welche neu gezeichnet werden müssen - das muss nicht das gesamte Fenster sein. Es gibt schließlich auch Anwendungen, die nicht neuzeichnen können (weil sie ihren Fensterinhalt nicht cachen) und einfach Teile des Inhalts (z.B. Graphen, Text, Benutzeroberfläche) neu berechnen und dann darstellen.
Es geht im Endeffekt um die Zeichenfunktionen, die müssen ja dann insoweit optimiert sein, das wirklich nur in dem Bereich der benötigt wird auch gezeichnet wird, sprich ist das Ende des Bereichs erreicht wird auch kein Code mehr ausgeführt (mal vereinfacht gesagt).

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #57 am: 26. November 2010, 15:32 »
Wir waren uns ja einig, das die Graka nur in ihrem eigenen Speicher schreiben kann (Hardwarebeschleunigung) und da wäre es dann besser, wenn der GUI-Server sich um den ganzen Kram kümmert auf welchem Treiber das Fenster gerade läuft und das sollte auch den Umzug eines Fenster von einem Desktop zu einem anderen erleichtern.
Ja. Der GUI-Server erzeugt den Puffer, ordnet ihn einer Grafikkarte zu und verwaltet alle im System existierenden Puffer.

Also wenn Hardwarebeschleunigung vorhanden ist, werde ich höchstwahrscheinlich auch genug Graka RAM haben um DoubleBuffering im Graka RAM zu machen und das würde heißen das jedes Mal neugezeichnet werden muss für ein Frame.
Auch Trident, WD90Cxx oder S3 Trio können Hardwarebeschleunigung (2D) und haben sehr wenig Grafikspeicher. Ist also ein schlechtes Kriterium. ;-) DoubleBuffering würde ich im hardwarespezifischen Treiber regeln, da der die Hardware kennt.

Bei dieser Methode wäre doch aber eine sehr hohe CPU Belastung vorhanden, wegen dem ständigen Neuzeichnen oder?
Irgendwie muss man ja noch den Fall abfangen, das sich gar nichts geändert hat.
Du kannst in der Schnittstelle zu Anwendungen festlegen, dass eine Anwendung den GUI-Server informieren muss, dass sich im Puffer etwas geändert hat. Das ist sinnvoll, weil wenn sich nichts ändert, brauchst du dir keinen Aufwand machen und Anwendungen können so eine große Menge an Änderungen durchführen, ehe es dargestellt wird (man bedenke Netzwerklatenz oder so).

Konkret zum VESA-Treiber: Du hast den Framebufferinhalt (z.B. 1024*768*4 Byte) genau zweimal, einmal im Grafikspeicher (wird vom CRTC ausgelesen und auf dem Bildschirm dargestellt) und eine Kopie davon im RAM.
Jede Anwendung ändert nun ihren eigenen Puffer (im unbeschleunigten Fall ist das also ein "Framebuffer" des Fensterinhalts) und meldet das an den GUI-Server.
Der GUI-Server meldet nun, da er die Übersicht über die Puffer hat, an den VESA-Treiber, welche seiner Puffer (verdeckte Fenster sind unnötig) er aktualisieren muss.
Der VESA-Treiber baut nun aus allen Puffern einen Frame in der Schattenkopie zusammen und kopiert den "im Block" in den Grafikspeicher. Kopierst du nur während VSYNC, hast du kein Tearing oder so und sparst dir einen Puffer. Bis zum nächsten Ereignis brauchst du nichts mehr kopieren, kostet also bis dann auch keine CPU-Zeit.

Damit brauchst du eine Schattenkopie des Framebuffers im System-RAM und hast trotzdem kein Tearing (der Grund für Double-Buffering), und da du nur auf der Schattenkopie im RAM arbeitest, hast du auch den Performancevorteil.

Es geht im Endeffekt um die Zeichenfunktionen, die müssen ja dann insoweit optimiert sein, das wirklich nur in dem Bereich der benötigt wird auch gezeichnet wird, sprich ist das Ende des Bereichs erreicht wird auch kein Code mehr ausgeführt (mal vereinfacht gesagt).
Das Neuzeichnen ist Aufgabe der Anwendung. Diese weiß am allerbesten, welche Teile wie neugezeichnet werden müssen und welche Objekte/Widgets davon betroffen sind. Im Endeffekt guckt die Anwendung nach, welche Widgets in dem vom OS genannten Bereich drin sind und ruft für jedes Widget eine Anweisung "zeichne dich neu". Das Widget wird von einem Toolkit (Qt, GTK) bereitgestellt und dort findet auch die Implementation statt, ob nun 2D- oder 3D-Beschleunigung genutzt wird oder auch nicht.

Die Zeichenfunktionen selbst haben von Bereichen keine Ahnung, sondern liegen eher in der Kategorie "gefülltes Rechteck in grün von (50|75) bis (90|105)". Diese Funktionen mit geeigneten Parametern optimal aufzurufen, ist wieder Aufgabe der Anwendung. Der GUI-Server hat damit nichts zu tun.

Gruß,
Svenska

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #58 am: 26. November 2010, 15:44 »
Nochmal zu dem Neuzeichnen.

Ein wenig Grafikprogrammierung habe ich schon mit Java gemacht (dank an die Uni ;) ).
Dir als Fenster wird ja eine Nachricht geschickt, das sich etwas geändert hat und man bekommt gleich noch einen Clipping Bereich dazu wo das war.
Ich dachte jetzt eigentlich das wenn man diesen Clipping Bereich als aktuellen Zeichenbereich nutzt, das dann ein Aufruf an RechteckFüllen() auch nur das "zeichnet" was in dem Clipping Bereich liegt?

Ich weiß auch aus Beobachtungen von Windows, dass dort die Fenster irgendwo gecacht werden. Denn wenn man bei einem Java Programm nicht neuzeichnet, aber ein Fenster einen Teil meines Fensters überdeckt und dann wieder "eggenommen" wird. Dann wird dieser Teil (der verdeckt war) zwar nicht neugezeichnet, aber der restliche Fensterinhalt ist noch da.
Da gibt es jetzt 2 Möglichkeiten, entweder wird jedes Fenster irgendwo gecacht oder Windows weiß sehr genau was sich wo geändert hat und dann wird auch der alte Frame weiterbenutzt und es wird nur das geändert was geändert werden muss.
(Wobei das Fenster cachen zwar mehr Speicher verbraucht, aber auch wesentlich schneller sein dürfte)

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #59 am: 08. January 2011, 15:25 »
Was du meinst, ist gerade kein Cachen des Bildschirminhalts, denn die Teile, die überdeckt wurden, sind kaputt. Der GUI-Server darf natürlich auch einfach schwarze Rechtecke darübermalen, aber das ist ja an sich egal.

Windows Vista/7 cachen übrigens den gesamten Fensterinhalt, um auch nicht-dargestellte Fenster als Vorschau in der Taskleiste anbieten zu können und außerdem bei Anwendungen, die gerade nicht reagieren, trotzdem das Fenster in den Vordergrund holen zu können.

Wird der Speicher knapp (wo auch immer), wirfst du nicht-dargestellte Fenster einfach weg und verlierst für dieses Fenster das Caching.

 

Einloggen