Sehr kurze Textanzeige auf dem Canvas

Für Fragen von Einsteigern und Programmieranfängern...
logo.holzaepfel
Beiträge: 8
Registriert: Sa 3. Apr 2021, 15:44
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit
Kontaktdaten:

Sehr kurze Textanzeige auf dem Canvas

Beitrag von logo.holzaepfel »

Liebe Leute und Larazus-Experten,

ich habe meine "Softwareentwickler Karriere" vor über 10 Jahren aus persönlichen Gründen ad acta gelegt und seit 2009 auch nicht mehr mit Delphi programmiert. Beruflich habe ich seitdem etwas gänzlich anderes gemacht (Logopädie)... nun bin ich aber in die Situation gekommen, eine Anwendung für die Therapie zu entwickeln, da ich nichts adäquates auf dem Markt finden konnte. Da ich schon früher häufiger von Lazarus gehört habe und es nah an mein früheres Delphi- Feeling heranreicht, dachte ich mir, dass ich damit arbeiten könne.

Folgende Aufgabe soll umgesetzt werden:
Ultrakurze Textanzeige - quasi ein kurzes Aufblitzen - eines Wortes. Die Dauer soll konfigurierbar sein. Damit wird die Lesegeschwindigkeit für bestimmte Patienten trainiert.
An sich habe ich die gesamte Anwendung schon geschrieben und getestet. Die Oberfläche funktioniert soweit und alles tut das, was es soll. Jedoch bekomme ich die "kritische Geschwindigkeit" noch nicht erreicht. Bei Anzeigezeiten von unter 50ms wird vereinzelt das "Zielwort" nicht ausgegeben. Bei Zeiten unter 30ms ist es ein Glücksspiel - maximal 2 von 10 Durchgängen werden angezeigt. Ich denke, dass ich da in der Programmierung wohl etwas nicht optimal umgesetzt habe... vielleicht könnt ihr mir dabei helfen.

Ich zeichne auf den Canvas des Mainforms:

Code: Alles auswählen

procedure TMainForm.DisplayText(const aText: string);
var
  iLeft, iTop: integer;
  iWidth, iHeight: integer;
begin
  iWidth := 0;
  iHeight := 0;

  // Breite und Höhe der Textausgabe ermitteln
  Canvas.GetTextSize(aText, iWidth, iHeight);

  // Position der Textausgabe ermitteln
  iLeft := (Canvas.Width - 4 - iWidth) div 2;
  iTop := (Canvas.Height - 40 - iHeight) div 2;

  // Text ausgeben
  Canvas.TextOut(iLeft, iTop, aText);
end;
In den aufrufenden Funktionen (drei Buttons für das aktuelle Wort in der Liste, das vorherige Wort in der Liste und dem nächsten Wort in der Liste) wird die Funktion DisplayText aufgerufen und dann ein Timer mit der konfigirierten Millisekundenanzahl aktiviert. In dessen OnTimer-Event lösche ich die Anzeige:

Code: Alles auswählen

procedure TMainForm.timDisplayTimer(Sender: TObject);
begin
  timDisplay.Enabled := False;
  Canvas.FillRect(Canvas.ClipRect);
end;     
Ist das ein grundsätzliches Problem im Canvas, dass eine Anzeigedauer unter 50ms zu kurz ist? Oder mache ich etwas verkehrt? Lässt sich hier noch etwas optimieren?

Vorab schon einmal vielen Dank für die Hilfe!

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 4569
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Niederösterreich
Kontaktdaten:

Re: Sehr kurze Textanzeige auf dem Canvas

Beitrag von af0815 »

Grundlegend würde ich mir 2 Bitmaps erstellen und die nach der geforderten Zeit übertragen. Damit wird das sicher stabiler, weil nicht das System erst alles jedesmal aufbauen muss.

OnTimer Events sind nicht besonders genau. Das ist eher eine Empfehlung, nach xx ms sich auszulösen. Man könnte das mit, wenn du Zeit hast, löse den Timer nach xx ms aus, wenn du Zeit hast, umschreiben.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

logo.holzaepfel
Beiträge: 8
Registriert: Sa 3. Apr 2021, 15:44
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit
Kontaktdaten:

Re: Sehr kurze Textanzeige auf dem Canvas

Beitrag von logo.holzaepfel »

Hallo af0815,

vielen Dank für deine Rückmeldung. Ich habe es oben nicht deutlich ausgeführt: ich habe eine Stringlist mit x Items unterschiedlich komplexer Wörter (von Ei bis Donaudampfschifffahrtsgeschellschaftsvorstandsvorsitzender ist alles möglich).

Auf meinem MainForm habe ich unten drei Buttons - einmal für das vorherige Wort aus der Liste, einmal zur Wiederholung des aktuellen Wortes und einmal für das nächste Wort.

Ich soll nun zwei Bitmaps erstellen, ein "leeres" und eines, das den jeweiligen Text darstellen soll? Sobald das Text-Bild angezeigt wird, zeige ich dann nach x Millisekunden das leere Bild?

Wegen des OnTimer-Events: Tatsächlich habe ich den Eindruck, dass dieses Event eher zu schnell ausgelöst wird - also noch während des "Schreibens" auf den Canvas.
Ich weiß nicht, ob es ein Canvas.BeginUpdate / EndUpdate gibt... ob es daran ggf. liegt.
Wie meinst du das mit "Man könnte das mit, wenn du Zeit hast, löse den Timer nach xx ms aus, wenn du Zeit hast, umschreiben."?

Benutzeravatar
Winni
Beiträge: 672
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.0.12, fpc 3.2
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: Sehr kurze Textanzeige auf dem Canvas

Beitrag von Winni »

Hi!

Also ein paar Anmerkungen:

Ich würde die Anzeige auf einem nicht-flüchtigen Canvas erstellen, also z.B. einem TImage.

Beim Anzeige-Start auf den Image.Canvas schreiben.
Beim Anzeige-Ende den Image.Canvas mit der Hintergrundfarbe füllen.

Timer ist begrenzt in der Auflösung und Betriebssystem -abhängig.
Ich würde das mit getTickCount64 lösen.

Code: Alles auswählen

Procedure TForm1.ShowString (s: string; MilliSec: Integer);
var startTime: Qword;
begin
startTime := GetTickCount64;
Image1.Canvas.TextOut (x,y,s);
repeat
until  GetTickCount64 - StartTime  <= MilliSec;
Image1.Canvas.FillRect (0,0,image1.width,Image1.Height);
end;
Hoffe es hilft.

Winni

logo.holzaepfel
Beiträge: 8
Registriert: Sa 3. Apr 2021, 15:44
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit
Kontaktdaten:

Re: Sehr kurze Textanzeige auf dem Canvas

Beitrag von logo.holzaepfel »

Hallo Winni,

ich habe das entsprechend umgebaut - nur erhalte ich nun keine Anzeige mehr: Ich habe auch aus dem "<=" ein ">=" gemacht, damit es nicht schon beim ersten Durchlauf rausspringt. Auch habe ich die Millisekundenanzahl auf 2000 gestellt.

Wenn ich die Schleife sowie den FillRect-Aufruf rauslasse, wird der Text angezeigt (und bleibt dann natürlich auch stehen...)

Edit: Wenn ich noch ein Application.ProcessMessages in der Schleife ergänze, funktioniert es.

Warf
Beiträge: 1562
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: MacOS | Win 10 | Linux
CPU-Target: x86_64
Wohnort: Aachen

Re: Sehr kurze Textanzeige auf dem Canvas

Beitrag von Warf »

Dein Hauptprobel ist das das Canvas nicht auf so hochfrequente zeichenoperationen ausgelegt, und regiert es kann passieren das es einfach nicht schnell genug reagieren kann. Unter Windows passiert wenn du Canvas.XXX aufrufst das folgende, der command wird als "Message" an das Windows control gesendet. Windows klappert dann in regelmäßigen abständen alle gesendeten Messages ab und führt die Zeichenoperation aus. Wann die Zeichenoperation ausgeführt wird ist also abhängig wann windows "zeit findet" diese operationen abzuklappern. Windows versucht zwar das das mehr oder weniger zügig passiert, doch es gibt keine garantien, die Zeichendauer ist abhängig von CPU last, anzahl der gesendeten Messages von allen Anwendungen auf dem System (also mehr oder weniger abbhängig von der Anzahl und komplixität an offenen Fenstern) und natürlich Leistungsstärke der CPU.

Wenn dein Programm also das "überzeichnen" zu schnell anfordert Kommen sie beide in die selbe Abarbeitungsprozedur und werden beide gleichzeitig ausgeführt und du siehst nur den effekt der letzten operation.
Alles unter so 100 ms ist nicht sehr verlässlich.

Du musst dir also alternativen außerhalb des Canvas suchen. Browser zum beispiel zeichnen alle komponenten selbst und umgehen dabei die OS MessageQueue, weshalb das folgende beispiel in Javascript wunderbar funktioniert:

Code: Alles auswählen

<!DOCTYPE html>
<html>
    <head>
        <script type="text/javascript">
            /** @param {number} timeout */
            function draw_on_canvas(timeout) {
                /** @type {HTMLCanvasElement} */
                const canvas = document.getElementById("canvas");
                /** @type {CanvasRenderingContext2D} */
                const ctx = canvas.getContext("2d");
                ctx.fillStyle = "white"
                ctx.font = "12px Arial";
                ctx.strokeText("Test", canvas.width / 2, canvas.height / 2);
                ctx.stroke();
                window.setTimeout(() => {
                    ctx.fillRect(0, 0, canvas.width, canvas.height);
                }, timeout);
            }
        </script>
    </head>
    <body>
        <canvas width="200" height="200" id="canvas"></canvas>
        <br />
        <button onclick="draw_on_canvas(10)">10 ms</button>
        <button onclick="draw_on_canvas(30)">30 ms</button>
        <button onclick="draw_on_canvas(50)">50 ms</button>
        <button onclick="draw_on_canvas(100)">100 ms</button>
    </body>
</html>
(Mit Pas2JS auch in Pascal möglich eine Website zu bauen). Ansonsten wenns nativ bleiben soll kannst du dir mal BGRABitmaps anschauen, es kann sein dasdie direkt über OpenGL oder ähnliches zeichnen, wenn nicht musst du dir die Hände schmutzlig machen und selbst mit Low-Level bibliotheken wie OpenGL oder SDL anfangen.


Abgesehen davon ist natürlich noch das Problem der Zeitlichen Auflösung da. Du hast kein Real-Time betriebsystem, also bist du hämmungslos dem Scheduler ausgeliefert. Und wenn der Scheduler entscheidet das dein Prozess von der CPU genommen wird, kann es mehrere Millisekunden dauern (bei mir c.a. 15-20) bis dein Code weiterlaufen kann. Richtig schlimm ist das wenn du Timer benutzt (wie in deinem code oder auch das Javascript beispiel oben), da Timer den event loop benutzen, welcher wenn er durch läuft die CPU zurückgibt (da ansonsten die CPU auslastung immer bei 100% wäre), und damit sehr ungenau wird. Sowohl mit dem Timer als auch mit dem Javascript code oben ist bei mir die Zeitdifferenz bei 30 ms delay z.T. auf 50 ms hochgegangen, mehr als 50% ungenauigkeit.
Mit einem Busywaiting approach wie in Winni vorgeschlagen hat (wenn man es richtig macht und >= statt <= verwendet), ist das zwar an sich besser, da du nicht unbedingt die CPU abgibst, aber der Scheduler kann auch so entscheiden das er deinen Prozess runter nehmen will.
Mit diesem kleinen Beispiel:

Code: Alles auswählen

var
  i: Integer;
  start: QWord;
begin
  for i:=0 to 100 do
  begin
    start := GetTickCount64;
    repeat
    until GetTickCount64-start >= 30;
    WriteLn(GetTickCount64 - start);
  end;
  ReadLn;
end.
Kann man das sehr schön sehen. Wenn sonst grade nix auf dem rechner läuft, er also eine CPU für sich alleine haben kann (und für das OS under der andere kram die anderen CPUs ausreichen) ist die Zeitdifferenz die ausgegeben wird immer 31 oder 32. Wenn ich jetzt mal ein paar Prozesse starte die die CPU last etwas hochtreiben, und dann das ganze noch mal ausführe, geht auch hier die Messung ab wieder ab und an auf 50 ms hoch, da der Scheduler den Prozess von der CPU schmeißt.

Langer Rede kurzer Sinn, mit dem Canvas kommst du nicht weit, du brauchst eine schnellere Rendering API (z.b. OpenGL oder SDL). Gleichzeitig musst du die chance veringern da dein Prozess währenddessen von der CPU geworfen wird, also nicht den Event Loop benutzen (also Busywaiting statt Timer) und wenn möglich nur auf einem rechner mit vielen CPUs (Kernen) und wenig anderen prozessen laufen zu lassen.
Aber selbst dann, kannst du für nichts garantieren, denn ein Nicht-Echtzeit betriebsystem ist inherent ungeignet um Präzise Zeitbedingungen einzuhalten

charlytango
Beiträge: 333
Registriert: Sa 12. Sep 2015, 12:10
OS, Lazarus, FPC: Laz 2.0 fixes FPC 3.2 fixes
CPU-Target: Win 32Bit, 64bit
Wohnort: Wien

Re: Sehr kurze Textanzeige auf dem Canvas

Beitrag von charlytango »

Bin kein Crack, aber vielleicht kann ich mit Hinweisen zur Lösung beitragen.

Das Thema Zeitscheibe war schonmal ein fieses Problem in einem meiner Projekte.

Das ließ sich letztlich damals lösen indem wir den Linux-Kernel selbst mit 1ms Zeitscheibe kompilierten. Und damit quasi eine Art Echtzeitsystem hatten.

Möglicherweise hast du einen alten PC auf dem du Linux installieren kannst.
evtl

Code: Alles auswählen

https://www.pro-linux.de/news/1/14750/echtzeit-kernel-f%C3%BCr-debian.html
Da wäre Lazarus sicher auch eine gute Entwicklungsbasis bei dem die einige Cracks hier unter Die Arme greifen können.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 4569
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Niederösterreich
Kontaktdaten:

Re: Sehr kurze Textanzeige auf dem Canvas

Beitrag von af0815 »

Ich gehe davon aus das Windows verwendet wird, zumindest deuten es die Posts mal an.

Der Windowsscheduler fast mehrer Aufrufe im System zusammen wenn es im im zeitlichen Kontext passt.

Grundlegend habe ich verstanden, das die Begriffe für eine definierte Zeit am Bildschirm erscheinen sollen.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

logo.holzaepfel
Beiträge: 8
Registriert: Sa 3. Apr 2021, 15:44
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit
Kontaktdaten:

Re: Sehr kurze Textanzeige auf dem Canvas

Beitrag von logo.holzaepfel »

Guten Morgen Winni, Warf, CharlyTango, af0815,

vielen Dank für die Rückmeldungen. Tatsächlich geht es, wie af0815 angemerkt hat, darum, dass ein vorgegebenes Wort aus einer StringList auf dem Bildschirm für eine definierte Dauer angezeigt wird und dann wieder verschwindet. Das Zielbetriebssystem ist Windows, es wäre aber genial, wenn es auch auf anderen Systemen laufen könnte.
Im großen und ganzen funktioniert die Anwendung auch schon passabel. Leider jedoch wird es bei den für die fortgeschrittenen Leser unter meinen Patienten mit der Anzeigedauer schwierig: wenn die Anzeigedauer auf unter 50ms reduziert wird, kommt es zunehmend zu Aussetzern - das Wort wird gar nicht erst auf dem Canvas ausgegeben, sondern "schneller" gelöscht als es auftaucht.

Wie es bislang funktioniert, könnt ihr hier sehen: https://www.logopaedie-holzaepfel.de/blitzwort.html
Da habe ich meine aktuelle Version online für meine Patienten stehen.
Den Quelltext stelle ich gerne ebenfalls zur Verfügung: https://www.logopaedie-holzaepfel.de/us ... Source.rar
Ich habe nicht vor, mich mit dem Programm irgendwie zu bereichern, sondern es soll als Unterstützung in der Therapie und ggf. zum Üben zuhause genutzt werden.

Ich hatte befürchtet, dass das Timer-Objekt Probleme machen könnte und dass der Canvas ggf. zu träge ist.
Nun habe ich den Timer rausgeworfen und durch das BusyWaiting ersetzt.
Ich hatte es zwischenzeitlich auch statt des Canvas des MainForms mit einem TImage versucht, aber da wurde es eher schlimmer statt besser - und irgendwie bekam ich es mit der Ausgabefläche nicht hin. Schlussendlich habe ich das TImage wieder verworfen.

Ich habe nun programmseitig eine Sperre für Anzeigezeiten unter 35ms vorgenommen. Mein Wunsch wäre allerdings, dass die Anzeigezeit auf bis zu 5ms reduziert werden könnte.
Gestern abend habe ich nun einige Stunden mit BGRABitmaps verbracht und experimentiert, aber ohne auch nur einen Funken an Anzeige zu erhalten (unabhängig von der Dauer). OpenGL oder SDL ist so fernab von allem, mit dem ich mich in den letzten 10 Jahren beschäftigt habe... ehrlich: dahinter steige ich nicht mehr!

Ich bin froh, dass ich das ganze schon so hinbekommen habe, wie es jetzt läuft (auch wenn es gefühlt nur ein "Hello World!" ist).
Falls jemand Zeit und Ahnung davon hat, würde ich mich sehr freuen, wenn ich noch etwas konkretere Unterstützung bekommen könnte.

Herzlichen Dank für eure Vorschläge und Anregungen. Euch frohe Ostern!

Edit: Link zum Sourcecode korrigiert
Zuletzt geändert von logo.holzaepfel am So 4. Apr 2021, 15:57, insgesamt 1-mal geändert.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 4569
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Niederösterreich
Kontaktdaten:

Re: Sehr kurze Textanzeige auf dem Canvas

Beitrag von af0815 »

Ich habe es mal probiert. Gesehen habe ich fast nichts. Zuerst habe ich mich auf den falachen Bereich konzentriert, dann kleine schwarze Schrift auf dunkelblauen Hintergrund. Heftig bei 45ms, aber ich kann das Wort sofort erkennen, wenn ich es sehe.

Ich verstehe was du meinst :D Nur auf etwas langsameren Rechnern wird dir das Betriebssystem immer einen Strich durch die Rechnung machen, wenn die Zeitspanne zu eng wird. Als Alternative würde mir da nur einfallen, das als Videostream dem System zu verkaufen. Dann kommst du auf Framerate herunter. Es wird alles funktionieren, wo das System mit den Frames selbst das Tempo bestimmen kann.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

logo.holzaepfel
Beiträge: 8
Registriert: Sa 3. Apr 2021, 15:44
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit
Kontaktdaten:

Re: Sehr kurze Textanzeige auf dem Canvas

Beitrag von logo.holzaepfel »

Moin af0815,

danke für die Rückmeldung. Ja, die Settings für Hintergrund(farbe) und Schriftart (inkl. Größe und Farbe) sind konfigurierbar... zum Glück für meine Patienten :)

Das mit dem Videosetting wäre evtl. etwas, aber da bin ich auch wieder raus... ich bin zu lange "fernab" der Entwicklung gewesen und so tief kann ich da echt nicht mehr eintauchen.

siro
Beiträge: 437
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 10
CPU-Target: 64Bit
Wohnort: Berlin

Re: Sehr kurze Textanzeige auf dem Canvas

Beitrag von siro »

Hallo,
den Source konnte ich leider nicht runterladen, Error 404

Dazu fällt mir jedoch ein: Die LCD Monitore haben ja eine Bildwiederholfrequenz von meist 60 Hertz.
Damit wäre also etwas innerhalb von 16,6 ms unter umständen garnicht sichtbar ?
So vermute ich, dass es mit einer Bitmap oder Image keine grossen Verbesserungen geben wird,
das habe ich aber nicht ausprobiert.

Ich habe aber grad mal einen Test des TTimer gemacht:
um zu zeigen wie ungenau der sein kann. Das geht leider nur unter Windows, weil die Unit Windows
benötigt wird um auf die Funktionen QueryPerformaceFrequency und QueryPerformaceCounter zuzugreifen.
TTimerTest.zip
(127.96 KiB) 15-mal heruntergeladen
Im Editfled kann man einen Wert in Millisekunden eingeben, dies ist dann der Timertakt (Interval im Objectinspektor)
Es werden nun die Zeitabschitte zwischen den Timeraufrufen exakt gemssen mit eine Auflösung bei mir von 100 Nanosekunden
Das geschieht zunächst im Hintergrund. Wenn man dann die Stoptaste drückt werden die ermittelten Werte in dier Liste eingetragen.
unter 20ms geht bei mir eigentlich garnichts.

Die Ausgabe, Anzahl der Messwerte in Caption, habe ich mal ein oder auch ausgeklammert,
das macht das Ergebnis nicht besser....

Dann habe ich meine Komponente mittels MMSystem Timer von Windows getestet.
Das sieht "WESENTLICH" besser aus. Da kann man wirklich mit einer Millisekunden arbeiten.
Aber ein anderes Testprogramm welches nur den Text eines Labels im präzisem Zeittakt ändert, ergab auch
dass Änderungen oftmals garnicht sichtbar werden.

Siro

Eine Ergänzung dazu:
Man müsste theoretisch die Anzeige mit dem V-SYNC synchronisieren, aber selbst dann ist man auf die Bildwiederholfrequenz angewiesen.
Es gibt aber Monitore bzw. Grafikkarten die höhere Wiederholraten haben/ermöglichen.

Für die Frames Per Second (FPS) usw.hier mal ein LINK:
https://wiki.freepascal.org/GraphicTest
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

Benutzeravatar
Winni
Beiträge: 672
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.0.12, fpc 3.2
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: Sehr kurze Textanzeige auf dem Canvas

Beitrag von Winni »

Hi!

Ganz andere Idee:

Da unter 25..30 ms alles unsicher ist, können wir versuchen, radikal den Overhead zumindest des Programms und der Umgebung zu reduzieren. Will meinen: Abschied von Lazarus (oder Delphi). Und fpc in den Turbo Modus versetzen.

Und dann :

Linux: Eine der echten Konsolen (Strg-Alt-F1..F6) benutzen
Windows: Die "DosBox" alias cmd auf Vollbildmodus setzen
Oder mit F8 in den abgesicherten Konsole-Modus starten.

So wird man schon mal ünnützes Aero-Gewimmel und erneutes Zeichnen von Desktop-Elementen los, was hier nur stört. Und CPU-Zeit frisst.

Da Du ja schon vor längerer Zeit mit Delphi und vielleicht auch mit Turbo Pascal rum gemacht hast, wirst Du Dich vielleicht erinnern.

Winni

Warf
Beiträge: 1562
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: MacOS | Win 10 | Linux
CPU-Target: x86_64
Wohnort: Aachen

Re: Sehr kurze Textanzeige auf dem Canvas

Beitrag von Warf »

Winni hat geschrieben:
So 4. Apr 2021, 14:45
Linux: Eine der echten Konsolen (Strg-Alt-F1..F6) benutzen
Windows: Die "DosBox" alias cmd auf Vollbildmodus setzen
Oder mit F8 in den abgesicherten Konsole-Modus starten.

So wird man schon mal ünnützes Aero-Gewimmel und erneutes Zeichnen von Desktop-Elementen los, was hier nur stört. Und CPU-Zeit frisst.

Da Du ja schon vor längerer Zeit mit Delphi und vielleicht auch mit Turbo Pascal rum gemacht hast, wirst Du Dich vielleicht erinnern.

Winni
Damit schießt du dir nur selbst ins Knie, da dann alle Sachen durch die CPU gezeichnet werden, während die Zeichenroutinen im Hintergrund von Windows und X11 (Linux) Hardwarebeschleunigt sind. D.h. statt CPU-Zeit zu gewinnen, fügst du einfach overhead zur CPU hinzu von sahcen die vorher auf der Grafikkarte gemacht wurden und jetzt über die CPU laufen müssen. Gleichzeitig hört X11 und alle andere Programme die laufen ja nicht auf zu arbeiten wenn du auf einem der Terminals bist (selbe gilt natürlich für windows mit ner DosBox), die laufen feucht fröhlich weiter im Hintergrund, du hast also die selbe CPU last wie vorher + die CPU last zum zeichnen auf der Konsole, das einzige was du sparst ist die Last auf der Grafikkarte, die bei normaler Nutzung des PCs mehr oder weniger irrelevant sein sollte.

Nicht das Zeichnen ist hier das Bottleneck, sondern der Scheduler, also wie viele Prozesse grade die CPU benutzen. Das "Aero-Gewimmel" wie du es nennst läuft fast ausschließlich über die Grafikkarte hat also absolut nix damit zu tun. Als Beispiel Raycasting spiele (die Rendering technologie von alten 2.5D Spielen wie dem dem originalen DOOM) laufen bei mir problemlos mit 1000 FPS selbst über die CPU (mit SDL um direkten zugriff zum Pixelbuffer zu bekommen), so lange es nicht vom Scheduler runtergeschmissen wird. Das problem ist das falls es vom Scheduler runtergeschmissen wird man mehrere millisekunden downtime oder so hat.

Ich hatte gestern ein paar Tests gemacht und auf meinem Laptop (i7 6 kerne) wurde wenn nix anderes als der Browser gleaufen ist, wurde die anwendung kein enziges mal von der CPU geworfen und konnte sehr genau im 30 ms tackt durch busywaiting arbeiten. Dann habe ich einfach mal eine hintergrundandwendung gestartet die ne menge CPU leistung frisst (eine Simulation um genau zu sein), und dann der Prozess regelmäßig runtergeschmissen.
Es hängt absolut nicht mit deiner eigenen anwendung zusammen, sondern mit den anderen anwendungen auf dem Rechner. Wenn ein Hintergrundprozess anfängt eine hohe CPU Last aufzubauen (z.B. ein regelmäßiger Virenscan anfängt, ein updater die Integrität von Dateien überprüft, etc), schmeißt der Scheduler dein Programm runter, egal wie sehr du den eigenen Footprint deines Programmes minimiert hast. Das Problem ist das man oftmals über solche Sachen keine Kontrolle hat. Grade wenn sowas auf Kundenpcs laufen soll kannst du dem Kunden ja nicht sagen er muss alle seine Update, Virenschutzprogramme, und sonstige Hintergrundprozesse beenden bevor er das Programm benutzt.

Wenn man kein RealTime Betriebsystem hat, kann man einfach nix gegen machen, außer hoffen das es nicht so oft auftritt und das die Anwendung im Durchschnitt wenigstens genau ist (Man kann ja auch die Zeit messen und so lange den Test wiederholen bis eine gewisse anzahl an akkuraten operationen durchgeführt wurde).

siro
Beiträge: 437
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 10
CPU-Target: 64Bit
Wohnort: Berlin

Re: Sehr kurze Textanzeige auf dem Canvas

Beitrag von siro »

Ich habe noch so Einiges rumprobiert,
aber ich sehe da keine Chance die Anzeige wie gewünscht hinzubekommen.

GetTickCount64 ist auch SEHR ungenau,
so habe ich das auch mal mit dem QueryPerformanceCounter gemacht
und siehe da, die Zeiten stimmen nun vom 1 bis xxx Millisekunden auf die Mikrosekunde genau,
nur leider nützt einem das garnichts....
In der Repeat Schleife wird noch:

Application.ProcessMessages;

aufgerufen und das ist eine wirkliche Bremse von so ca. 15 Millisekunden.
Nimmt man das raus, wird nicht mehr richtig "restauriert"
aber selbst mit Tricks wie Refresh usw. ist der Text manchmal sichtbar manchmal nicht.

Code: Alles auswählen

  // Text ausgeben
  Canvas.TextOut(iLeft, iTop, aText);
  //  Canvas.Refresh;  // SIRO: sofort restaurieren

{   SIRO  ausgeklammert
  //Cleanup Routine
  iStartTime := GetTickCount64;
  repeat
    iRunTime := GetTickCount64;
    Application.ProcessMessages;
  until iRunTime - iStartTime >= fDisplayInterval;
}

// SIRO :  ersetzt durch:
// Das Timing sollte nun im Mikrosekundenbereich stimmen
  QueryPerformanceCounter(iStartTime);
  iEndTime:=iStartTime + Round(fDisplayInterval * performanceFrequency / 1000);
  repeat
    QueryPerformanceCounter(iRunTime);
//    Application.ProcessMessages;   // !!!!!!!! <==== hier ist eine BREMSE, so ca. 15 Millisekunden  !!!!!
// nimmt man das raus, geht es aber so gut wie garnicht mehr.......
  until iRunTime > iEndTime;

  // SIRO:  Testweise die Zeit in die Listbox eintragen
  Listbox1.items.add(FloatToStr((iRunTime-iStartTime)/performanceFrequency));

  Canvas.FillRect(Canvas.ClipRect);
//  Canvas.Refresh;  // SIRO: sofort restaurieren     
Mein FAZIT: Das scheint wirklich mit der Aktualisierungsrate des gesamten System Grafikkarte+Monitor zusammenzuhängen.
Also 60 Hz ==> 16,6ms

Das ist wirklich Schade, da ich auch lange Zeit in der Logopädischen Behandlung war, wäre es auch mich mich sehr interessant gewesen.
Solche Tests hatte ich übrigens nicht dabei, generelle Leseübungen jedoch schon. Ich war erstaunt wie weit das Fach Logopädie ausgedehnt ist.

Ich habe eben nochmal geschaut wegen Monitoren:
Es gibt inzwischen Monitore mit 60 120 144 165 240 Hz Wiederholfrequenz, ich vermute damit wird die Anzeige garantiert besser. (Zeitgenauer)
Ich hab leider keinen "schnellen" Monitor um es mal zu testen, obwohl mich das grade auch brennend interessiert....

Siro
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

Antworten