[skindesigner] Verständnisfrage - OSD-Aufbau

  • Hallo zusammen,


    ich versuche mich gerade in der Optimierung des OpenGL-OSD. Auf meinem Tanix TX6 mit softhddevice-drm läuft das estuary skin zwar, aufgrund der Animationen und der Menuaktualisierungen aber etwas träge. Ich habe z.B. gemerkt, dass die Aktualisierung des Hauptmenüs wegen Uhrzeit etc. ca. 350ms pro Flush benötigt.

    Da habe ich mir die Frage gestellt, ob denn das ganze OSD gemacht wird, oder ob nur die neuen Bereich neu gezeichnet werden wie es z.B. LCars macht.

    Tatsächlich scheint es, als würden alle vorhandenen pixmaps, egal ob dirty oder nicht, gerendert werden. Ich habe das probehalber getestet, indem ich vorher eine Abfrage auf IsDirty eingebaut habe. Es geht dann bedeutend schneller (~30ms), aber die Bereiche werden dann natürlich nicht gelöscht und es wird einfach drübergezeichnet.

    Wenn ich den betroffenen Bereich vorher löschen lasse, wird zwar nichts mehr übereinander gezeichnet, allerdings verschwindet auch der Hintergrund und es fehlen Teilbereiche des OSD.


    Jetzt meine Fragen: Wie wäre der planmäßige OSD-Aufbau? Soll das OSD immer komplett mit allen pixmaps neu geflusht werden oder sollen nur die dreckigen Bereiche gezeichnet werden?

    Ist es für Skindesigner erforderlich, jedesmal alles zu zeichnen, d.h. auch den Hintergrund oder gibt es hier andere Möglichkeiten, damit wirklich nur die dreckigen Bereiche (mit allen Layern) gezeichnet werden?


    Ich stecke in Skindesigner (noch) nicht drin, möchte das aber gerne verbessern. Stellt sich nur die Frage, ob in Skindesigner oder im Ausgabeplugin.

    Grundsätzlich müsste ich aber zuerst wissen, wie die osd-Klasse das generell vorsieht...


    Ich hoffe, mein Anliegen ist soweit verständlich ;)


    Wenn man so eine Art dirty-Area handling einbauen könnte, wäre das ein enormer Performanceschub...


    Gruß

    Andreas

  • Hallo kamel5 ,


    danke für deine Antwort. Leider habe ich von skindesigner noch sehr wenig Ahnung und überlege deswegen, ob ich das testweise im Ausgabeplugin mache.

    Dann würde man sehen, welchen Effekt es überhaupt hat. Ich stelle mir das so vor:

    - Bevor die Pixmaps beim Flush auf das OSD gerendert werden, erstmal die wirklichen dirty Bereiche herausfinden, z.B. Feld für Uhrzeit

    - Beim Rendern alle sauberen pixmaps prüfen, ob eine der dirty Areas im Bereich der pixmap liegt und nur diese Ausschnitte der "sauberen" (Hintergrund-)Pixmap rendern


    Ich denke, das müsste relativ schnell und einfach umsetzbar sein.


    Bzgl. LCars kann kls das vielleicht sagen, was da bei Aktualisierungen ins OSD geschoben wird.

    Ich denke, das ist wirklich auch eine Eigenheit vom GL-OSD, da hier der Einfachheit halber sowieso immer das ganze OSD (als texture) gerendert wird.

    Eine Prüfung auf dirty areas findet m.E. nicht statt. Auf starker Hardware ist das wohl auch kein Problem.

    Wenn es aber grundsätzlich so sein sollte, dass das OSD bestehen bleibt und nur beim Close oder Neuaufbau gelöscht wird und solange es offen steht nur Bereiche überrendert werden, könnte man hier bestimmt wesentlich optimieren. Im Ausgabedevice oder m.E. besser im Skin-Plugin selbst.

    Gruß

    Andreas

  • Hallo,


    da ich mich zur Zeit um den skindesigner kümmere, werde ich mal darauf antworten.

    Ich habe z.B. gemerkt, dass die Aktualisierung des Hauptmenüs wegen Uhrzeit etc. ca. 350ms pro Flush benötigt.

    Da habe ich mir die Frage gestellt, ob denn das ganze OSD gemacht wird, oder ob nur die neuen Bereich neu gezeichnet werden wie es z.B. LCars macht.

    Soweit ich das bisher verstanden habe, funktioniert das so: Das OSD wird vom VDR selbst oder vom Ausgabedevice bereitgestellt. Ein Zeichnen einer Pixmap bewirkt ja nicht gleich ein Ausgeben. Erst das Flush rendert dann den Teil und gibt ihn aus. So kann der Renderer feststellen, ob sich z.B. diese Pixmap geändert hat und diese dann gezielt ausgeben. So sollte es auch beim skindesigner funktionieren.

    Da ich vom skindesigner längst nicht alle Internas verstanden habe, wäre es durchaus denkbar, das das nicht immer richtig funktioniert und der Renderer denkt, das Teile dirty sind, die es eigentlich nicht sind.

    Im Endeffekt könnte Dir diese Frage, wie der skindesigner das händelt, wahrscheinlich nur der originale Autor beantworten.

    Ich selbst fühle mich da im Moment zeitlich auch außerstande, mich mit diesem Thema tiefgründiger zu befassen.


    Wenn Du da Optimierungen für den skindesigner findest, kann ich das gerne ins git aufnehmen.


    Grüße

    kamel5

    VDR 2.6.1: ASUS Prime X470-PRO, Ryzen 7 2700, 64GB, 6TB HD, GT1030, Fedora 36 Kernel 5.19 X86_64, Devicebonding 2 x 1 auf 2, TT6400, DVBSky S952 V3

    Git-Repo: gitlab.com/kamel5

  • - Bevor die Pixmaps beim Flush auf das OSD gerendert werden, erstmal die wirklichen dirty Bereiche herausfinden, z.B. Feld für Uhrzeit

    - Beim Rendern alle sauberen pixmaps prüfen, ob eine der dirty Areas im Bereich der pixmap liegt und nur diese Ausschnitte der "sauberen" (Hintergrund-)Pixmap rendern

    Da habe ich mir die Frage gestellt, ob denn das ganze OSD gemacht wird, oder ob nur die neuen Bereich neu gezeichnet werden wie es z.B. LCars macht.

    Nachtrag:

    Bei LCARS ist es so, das da das OSD selbst der "Arbeitsbereich" ist, also direkt in das OSD gezeichnet wird (es wird also nicht mit Pixmaps gearbeitet).

    Hier muss der Renderer also selbst herausfinden, was sich im Gesamt-OSD geändert hat.


    Grüße

    kamel5

    VDR 2.6.1: ASUS Prime X470-PRO, Ryzen 7 2700, 64GB, 6TB HD, GT1030, Fedora 36 Kernel 5.19 X86_64, Devicebonding 2 x 1 auf 2, TT6400, DVBSky S952 V3

    Git-Repo: gitlab.com/kamel5

  • Ein Zeichnen einer Pixmap bewirkt ja nicht gleich ein Ausgeben. Erst das Flush rendert dann den Teil und gibt ihn aus. So kann der Renderer feststellen, ob sich z.B. diese Pixmap geändert hat und diese dann gezielt ausgeben. So sollte es auch beim skindesigner funktionieren.

    Ich denke, das macht der Skindesigner auch richtig. Das Problem ist nur, dass beim GL-OSD auch Teile, sprich Hintergründe, von pixmaps gerendert werden müssen, die sich nicht geändert haben und deshalb auch nicht als dirty markiert sind. Sonst stimmt die Ausgabe nicht. Der Skindesigner könnte natürlich schon prüfen, ob saubere pixmaps unter geänderten Bereichen liegen, dann müsste aber auch auf der sauberen pixmap der Bereich schon markiert werden, sonst hat das Ausgabeplugin wieder die Arbeit um nicht die komplette pixmap rendern zu müssen.


    Ich denke also, das muss ich am Ausgabeplugin machen.


    Gruß

    Andreas

  • Der Skindesigner könnte natürlich schon prüfen, ob saubere pixmaps unter geänderten Bereichen liegen, dann müsste aber auch auf der sauberen pixmap der Bereich schon markiert werden, sonst hat das Ausgabeplugin wieder die Arbeit um nicht die komplette pixmap rendern zu müssen.

    Das wird aber in anderen Skins auch nicht gemacht.

    Im Endeffekt kann die Vorgehensweise doch nur so sein:

    Es wird festgestellt, z.B. eine Pixmap hat sich geändert. Dann müssen natürlich auch alle anderen Layer, die darunter und darüber liegen, beim Rendern mit berücksichtigt werden. Ich wüsste jetzt auf Anhieb nicht, wie das ein Skin leisten sollte.

    Ich denke also, das muss ich am Ausgabeplugin machen.

    Um hier allgemeingültig zu bleiben, muss das wohl der Weg sein.


    Grüße

    kamel5

    VDR 2.6.1: ASUS Prime X470-PRO, Ryzen 7 2700, 64GB, 6TB HD, GT1030, Fedora 36 Kernel 5.19 X86_64, Devicebonding 2 x 1 auf 2, TT6400, DVBSky S952 V3

    Git-Repo: gitlab.com/kamel5

  • Bei LCARS ist es so, das da das OSD selbst der "Arbeitsbereich" ist, also direkt in das OSD gezeichnet wird (es wird also nicht mit Pixmaps gearbeitet).

    Hier muss der Renderer also selbst herausfinden, was sich im Gesamt-OSD geändert hat.

    Siehe dazu osd.h:

    Die OSD-Implementierung bekommt also über RenderPixmaps() nur den Bereich, der sich verändert hat.

  • Erstmal danke für eure Beiträge. Ich habe das jetzt mal hier in mein openglosd eingebaut.


    Beim Flush wird jetzt zuerst der von allen dirty pixmaps umschlossene Bereich ermittelt. Dann wird nur dieser Bereich gelöscht und alle pixmaps, die damit eine Überschneidung haben, gerendert. Mit glScissor wird der Bereich dann am Ende auf den dreckigen Bereich jeweils beschränkt.

    Man kann das Spiel sicher noch weiter treiben und ein array aus den dirty pixmaps machen, aber Stand jetzt ergibt sich schon eine bessere Performance.


    Mir ist dabei aufgefallen, dass beim skinnopacity immer die pixmap auf dem Layer 0 mit der vollen Größe als dirty markiert wird, obwohl beim HITK Down "nur" die neue Menüzeile dreckig sein sollte? Ich habe noch nicht gefunden, wer dafür verantwortlich ist, aber damit wird bei meiner aktuellen Implementierung auch das ganze OSD neu gerendert, obwohl es eigentlich nicht sein müsste. Das müsste wohl in skinnopacity angepasst werden.

    Wenn die Uhrzeit bei offenem Menu aktualisiert wird, passt es. Dann wird wirklich nur der Bereich mit der Uhrzeit neu gerendert.

    Meine Vermutung ist, dass da wegen dem Video-Fenster ein Clear auf die gesamte Fläche gemacht wird. Aber evtl. kennt sich da jemand besser aus.


    Skinopacity und skindesigner sind aber schon mal flüssig benutzbar.


    Wenn es jemand ins openglosd.cpp der anderen softhddevice*-Plugins übernehmen und/oder testen möchte - gerne Rückmeldung.


    Gruß

    Andreas

  • Mir ist dabei aufgefallen, dass beim skinnopacity immer die pixmap auf dem Layer 0 mit der vollen Größe als dirty markiert wird, obwohl beim HITK Down "nur" die neue Menüzeile dreckig sein sollte?

    Pixmaps mit Layer 0 sollte es nicht geben, Layer 0 ist ein spezieller Layer, der nicht alles kann.

    Bei "HITK Down" und "HITK Up" wird jedesmal auch die Funktion Clear() aufgerufen. Und in der wird bisher die komplette Menü-Liste gelöscht.

    Mit dem Video-Fenster sollte es nichts zu tun haben.

    Folgende Änderung sollte das unterbinden:

    Code
    1. void cNopacityDisplayMenu::Clear(void) {
    2. if (menuFadeOutTime)
    3. return;
    4. DELETENULL(detailView);
    5. // menuItems.clear(); <- Änderung
    6. }

    Du könntest mal testen, ob das Problem dadurch behoben ist. Wenn ja, würde ich im Anschluss mal schauen, ob sich dadurch Nebenwirkungen ergeben und es dann ins git aufnehmen.


    Grüße

    kamel5

    VDR 2.6.1: ASUS Prime X470-PRO, Ryzen 7 2700, 64GB, 6TB HD, GT1030, Fedora 36 Kernel 5.19 X86_64, Devicebonding 2 x 1 auf 2, TT6400, DVBSky S952 V3

    Git-Repo: gitlab.com/kamel5

  • Danke, ich werde es testen. Hört sich aber arg danach an, als hätte es damit zu tun.

    In der Theorie sollte das clear überflüssig sein, da ja die neu zu zeichnenden Bereiche eh gelöscht werden.


    Gruß

    Andreas

  • Hallo rell ,


    die obige Änderung hilft nicht.

    Ich habe bei mir mal einige Debug-Meldungen eingebaut und das Clear() wird nur beim seitenweisen Scrollen aufgerufen.

    Ich muss also tatsächlich mal tiefgründiger suchen, ob ich da was finde, das zu diesem Verhalten passt. Das könnte aber etwas länger dauern.


    Eins würde mich aber trotzdem noch interessieren: Tritt dieses Verhalten auch auf, wenn alle Animationen abgeschaltet sind?


    Grüße

    kamel5

    VDR 2.6.1: ASUS Prime X470-PRO, Ryzen 7 2700, 64GB, 6TB HD, GT1030, Fedora 36 Kernel 5.19 X86_64, Devicebonding 2 x 1 auf 2, TT6400, DVBSky S952 V3

    Git-Repo: gitlab.com/kamel5

  • kamel5

    Ich glaub ich habs gefunden. Es liegt an openglosd.cpp.

    Im speziellen daran, dass bei einem DestroyPixmap immer die komplette Hintergrundpixmap mit SetDirty() als dirty markiert wird -> https://github.com/rellla/vdr-…dirty/openglosd.cpp#L2718

    Das ist kein Problem, wenn man immer das ganze OSD neu rendern lassen will, aber schlecht, wenn man nur die Teilbereiche machen will.

    Im VDR Original wird hier sinnvollerweise nur der Bereich des Hintergrunds als dirty markiert, der sich auch mit den gelöschten pixmaps überschneidet.


    Evtl. reicht es, das SetDirty() hier einfach rauszunehmen, da sich das openglosd um diese Bereiche kümmert und die Pixmaps entsprechend neu zeichnet.

    skinnopacity scheint damit zu funktionieren, skindesigner (noch) nicht.


    Konsequenter wäre es aber, wenn openglosd auch MarkViewportDirty() und MarkDrawportDirty() mit den ensprechenden Funktionen nutzen würde, wie es das OSD von VDR macht. Dann könnte man sich evtl. beim letzten Zusammensetzen des OSD sparen, das dirtyRect zu finden. Und man wäre "VDR-konform". Und skindesigner würde wohl auch klappen...


    Jedenfalls gibt das schon wieder einen Performanceschub ;)


    Gruß

    Andreas

  • So, ich denke vorerst passt es so.

    Mit skinnopacity und skindesigner habe ich bisher keine Probleme festgestellt. Geht deutlich flotter jetzt.

    Bei den Skins von VDR stimmt noch was nicht ganz, wenn ich im Einstellungen->OSD Menü in der Skin-Zeile mit Links und Rechts durch die Skins scrolle. Da passt dann was mit der Kopfzeile nicht. Vielleicht schau ich mir das auch irgendwann nochmal an...


    Und ja, du kannst es von der Liste streichen ;)


    Gruß

    Andreas