Ok, ich möchte dir nicht vorwerfen den Quellcode nicht ganz gelesen zuhaben, schließlich ist es schon ziemlich viel.
Das Prinzip wie die GUI momentan entworfen ist sieht so aus:
- Es gibt einen Toplevel-Container der am Anfang angelegt und einem GUI-Objekt zugeordnet wird. Dieses Objekt ist also für jedes Widget auf sich verantwortlich vom Focus/Event-handling bis zum zeichnen.
- Es gibt eine Hauptschleife in der zwei Punkte regelmäßig abgefragt werden zum eine "gui.update()" und "gui.draw()". In beiden Methode befindet sich eine Top-Bottom Strucktur, sprich das Toplevel-Widget ruft die Update/Draw-Methoden der Kinder auf und die deren Kinder.
- Die Draw-Methode "blittet" bei jedem Aufruf nur das zwischengespeicherte Widget, es wird also kein neues Surface erstellt.
Was im übrigen nicht anährend so teuer ist wie du vermutest, da sie erstens immer nur in der Größe vom Widget erzeugt werden, man bräuchte schon ein einziges Widget in der Größe des Screens bei Vollbild um das zuereichen und zweitens ist abgesehen vom Speicherverbrauch des Python Objektes nicht wesentlich höher der GC ist zumindest schnell genug. Zudem wird der Speicherverbrauch nochmal durch die genutzten Subsurfaces minimalisiert, weil ich immer nur die Referenzen auf den Speicher halte und ihn nicht dupliziere.
- Ein Neuzeichnen(redraw) muss entweder angefordert oder erzwungen werden, erst dann wird ein neues Surface erstellt, theoretisch könnte man das erzeugen noch etwas umgestalten, sollte aber nicht ins Gewicht fallen.
In einem Test ist mir auch aufgefallen das das erzeugen eines neuen Surfaces fast genauso viel Leistung braucht wie es mit "fill" wieder schwarz zu färben. Als Optimierung könnte ich mir aber noch vorstellen das man immer nur den geänderten Ausschitt ermittelt, aber das ist sicher nicht sehr ein einfach zu ermitteln - und lohnt sich warscheinlich nicht.
- Ein "redraw" wird von einem Widget ausgelöst auf welchem ein Event stattfindet, also nicht bei sowas wie "Maus bewegt sich über dem Widget", aber bei Maus Ein/Aus-tritt auf dem Widget, halt immer wenn sich das aussehen des Widgets verändert.
Hier hatte ich mir überlegt sowas in der Art wie den
hier vorgestellten Caching zu verwenden. Da Beispielsweise bei einem Button nur vier Status existieren, also wenn einer davon schon erzeugt wurde könnte man sich damit ersparen nochmal einen zu erzeugen. Brauch aber wieder etwas mehr Speicher.
- Neuzeichnen anfordern bedeutet das ein Kind-Objekt an seine Eltern weiter gibt das es verändert wurde und das entsprechende Elternteil ebenfalls neu gezeichnet werden muss. Beispiel: Toplevel - Window1 - HBox - Button1, Button2, Button3. Toplevel - Window2 -...
Wird Button2 geklickt, wird ein "redraw" angefordert und an HBox weitergeleitet, HBox leitet diesen Request an Window1 und dann an Toplevel weiter. Zuerst wird also Toplevel.draw() aufgerufen dieses hat ein angefordertes "redraw", also läst es alle Kinder-Widgets neuzeichnen. Window2 ist nicht verändert wurden, hat keinen "redraw" (nötig), also wird der alte Stand "geblittet". Window1 wurde geändert also wird der Rahmen neugezeichnet und dann alle Kinder-Widgets wieder gezeichnet. Es gibt nur eines also wird HBox auf ein "redraw" geprüft, dieses liegt vor also wird die Box neu gezeichnet. Die Box geht wiederum alle Kinder-Widgets durch und zeichnet nur Button2 neu, die anderen werden im alten Stand geblittet.
- Neuzeichnen erzwingen bedeutet aller Kinder-Widgets und deren Kinder-Widgets werden neugezeichen. Also Top-Bottom statt wie bei dem Anfordern wo es eine Bottom-Top Strucktur ist. Wird vorallem bei dem ScrollArea benötigt, da beim ändern des Inhaltes sich eventuell die ScrollBars verschieben.
Warum das blitting allerdings dermaßen teuer ist verstehe ich auch noch nicht so richtig. Ich verstehe ja warum es mehr braucht als der Amiga

- schließlich haben ich 32-bit Bilder, die Bildschirmauflösung war wohl damals auch noch etwas geringer und das ganze spielte sich nicht in einem SDL-Fenster ab. Unter C ist das "blitting" auch nochmal um einiges schneller, Beispielprogramme die ich gesehen hatte kamen auch mit dauerhaftem "blitten", also ohne ein "redraw"-System nicht über 25% Leistung des oben genannten CPUs und das bei 60 fps.
Ein Punkt der das ganze noch etwas verlangsamt, sind die automatisch generierten Bilder die ich erzeuge. Aber zur Information, ich lese die Bilder, also das Themeset, einmal zu Beginn aus. Dazu verwende ich XML-Schablonen welche definieren was genau von den einzelnen Bildern benötigt wird. Im Grundprinzip wird jedes Bild in neun Teile zerlegt, d.h. in Ecken, Seiten und die Mitte. Dann gibt es zum zeichnen dieser Bilder auf einen bspw. Button drei Methoden welche zum strecken der Seiten und der Mitte ausgewählt werden können. So wäre 2 Methoden eine automatische Skalierung auf die Größe des Buttons und die dritte ist sozusagen ein "fill" was die Teile aneinander reiht, also kopiert. Hier werden immer nur die Referenzen auf die Grafik benutzt. Dadurch kann ich die Widgets in beliebig viele Größen rendern.
Dennoch laut cProfile nur ein heißer Tropfen auf dem Stein im Vergleich zu dem was das "blitten" verbraucht.
Last but not least:
pygame.display.flip() lohnt sich nur bei Hardware-Rendering, wie ich der
Dokumentation entnehme ist pygame.display.update() für Software-Rendering besser geeignet und danach richtet sich auch mein Test-Programm:
Code: Alles auswählen
if SCREEN_FLAGS & pygame.HWSURFACE:
pygame.display.flip()
else:
pygame.display.update()
Der
Dokumentation von SDL entnehme ich noch SDL_DOUBLEBUF
Enable hardware double buffering; only valid with SDL_HWSURFACE.
, sprich es kann mit in den "Screenflags" mit angegeben werden. Wie du meiner
test.py entnehmen kannst ist das auch schon geplant. Auch andere Flags muss ich erst noch durchgehen ein paar habe ich noch gefunden die "ein schnelleres Zeichnen ermöglichen" aber jede dieser Flags hat auch immer einen Haken, welches das zeichnen in anderen Fällen drastisch verschlimmern kann.
Falls davon mal jemand eine Übersicht hat immer her damit.
Ich hoffe ich konnte dir mein Zeichen-System etwas näher bringen und danke für dein immer noch bestehendes Interesse, obwohl du mit SDL nicht viel am Hut hast.
MfG Xynon