PL Text Engine: Mit Buffer oder ohne Buffer ?

Rund um die LCL und andere Komponenten
Antworten
pluto
Lazarusforum e. V.
Beiträge: 7192
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

PL Text Engine: Mit Buffer oder ohne Buffer ?

Beitrag von pluto »

Hallo,
ich habe heute damit angefangen, die Scroll Funktion einzubauen. Läuft auch soweit ganz gut. Jedoch bin ich auf ein Problem gestoßen. Für die es mehrere Lösungen gibt aber keine gefällt mir.
Hier erst einmal das Problem:
Was mache ich mit Objekten, die zu groß sind um sie zu zeichnen, klar abschneiden, aber wie ?

Lösung Eins
Hier ist mir die Lösung gekommen: Das Komplette Dokument in einem Grafik Buffer zu Rendern. Allerdings würde das mehr Speicher verbrauchen. Für das Scrollen währe das, die beste Lösung. Meiner Meinung nach. Aber andere Funktionen hätten Probleme. z.B. wenn ich das Dokument, später Dynamisch verändern möchte. Oder auch das es Langsamer währe, weil ich beim Laden, erst einmal alles in einem Buffer kopieren müsste und dann aus diesem Buffer nur den Sichtbaren Teil rauß kopieren. Allerdings würde das meine ich später nicht unbedingt Langsamer werden.
Was die Geschwindigkeit angeht, da gibt es gewisse Optimierungs Möglichkeiten. z.b. ich zeichne gleich von Anfang an nur den Sichtbaren Teil und Kopiere es dann....
Die Größe des Buffers wird sowieso vorher berechnet.

Lösung Zwei
Ich würde eine eigene Funktion schreiben, um ein Viereck zu zeichnen. Ist sowieso geplannt. Aber erst für Später.
Allerdings hätte ich hier das Problem: Wie mache ich das mit einem Text Objekt, was zu groß ist ?

Lösung Drei
Ich könnte das Text Objekt, einfach in einem Intern Buffer schreiben und den Sichtbaren Teil rauß kopieren.

Bei Lösung Zwei und Drei hätte ich höchsten Probleme zu berechnen, wie viel Sichtbar ist. Im Moment verschiebe ich die Objekte nur in den Negativen Bereich. Wenn ich Lösung Eins nehmen würden, bräuchte ich das nicht mehr. Würde jedoch gewisse Nachteile in Kauf nehmen.

Ich hoffe ihr habt das Problem verstanden. Habt ihr weitere Vorschläge ? Lösungen ? Verbesserungen ?
MFG
Michael Springwald

martin_frb
Beiträge: 588
Registriert: Mi 25. Mär 2009, 21:12
OS, Lazarus, FPC: Laz trunk / fpc latest release / Win and other
CPU-Target: mostly 32 bit

Re: PL Text Engine: Mit Buffer oder ohne Buffer ?

Beitrag von martin_frb »

IMHO sollte grundgesetzlich nur gezeichnet werden was gebraucht wird. Für Textausgabe gibt es Funktionen mit clipping. (Müsste nach schauen welche, weiß gerade den Namen nicht....)

pluto
Lazarusforum e. V.
Beiträge: 7192
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: PL Text Engine: Mit Buffer oder ohne Buffer ?

Beitrag von pluto »

Für Textausgabe gibt es Funktionen mit clipping
Du meinst TextDraw bzw. TextOut....
TextDraw habe ich mir schon angeschaut. Eventuell kann ich da wegen dem clpping nutzen. Bei TextOut müsste das meine ich auch gehen. Ich mach dazu einige Tests.
Daher kann ich eventuell auf den Intern Buffer also doch verzichten.

Die Windows Komponenten kommen auch alle ohne aus.....
MFG
Michael Springwald

martin_frb
Beiträge: 588
Registriert: Mi 25. Mär 2009, 21:12
OS, Lazarus, FPC: Laz trunk / fpc latest release / Win and other
CPU-Target: mostly 32 bit

Re: PL Text Engine: Mit Buffer oder ohne Buffer ?

Beitrag von martin_frb »

oder:
ExtUTF8Out
ExtTextOut

pluto
Lazarusforum e. V.
Beiträge: 7192
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: PL Text Engine: Mit Buffer oder ohne Buffer ?

Beitrag von pluto »

Allerdings hätte ich dann nur noch Probleme mit Grafiken.
Z.B. möchte ich eine sehr Große Grafik Anzeigen. Damit sie nicht über die Render gezeichnet wird, müsste ich hier also auch wieder ermitteln, wie viel Platzt zu Verfügung steht und nur den Sichtbaren Bereich kopieren.

Müsste ich mir überlegen. Im Moment stellt das noch kein Problem da, aber ich möchte z.b. auch später Container verschachteln können. Da währe diese Clipping Funktion ganz Hilfreich um Grafik Fehler zu vermeiden.

Ich habe mir den Soruce-Code von DrawText(hieß die so ?) angeschaut. Diese Funktion währe zu Langsam... selbst wenn ich sie nur für das Clipping einsetzten würde.
MFG
Michael Springwald

pluto
Lazarusforum e. V.
Beiträge: 7192
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: PL Text Engine: Mit Buffer oder ohne Buffer ?

Beitrag von pluto »

Ich habe jetzt auch das "Horizontale Scrollen" eingebaut. Da ist im Übrigen der gleiche Logische Fehler aufgetreten: So wie es aussieht müsste ich jetzt die "Clipping Funktion" einbauen.

Außerdem Flackert es wenn ich den Slider(egal ob Horizontal oder Vertikal) mit der Maus bewege. Da hilft meiner Meinung nach nur ein "Intern Grafik Buffer". Eventuell gibt es auch die Möglichkeit einen Cache einzubauen. Die Frage ist wie soll der Aussehen ?

Bei meinem "BB Code Parser" habe ich das so gelöst, dass jedes Objekt ein eigenen Grafik Buffer hat. Im Moment wird ja alles in einem Canvas gezeichnet. Alleine schon wegen dem Flackern.... Oder habt ihr noch andere Vorschläge ?
MFG
Michael Springwald

martin_frb
Beiträge: 588
Registriert: Mi 25. Mär 2009, 21:12
OS, Lazarus, FPC: Laz trunk / fpc latest release / Win and other
CPU-Target: mostly 32 bit

Re: PL Text Engine: Mit Buffer oder ohne Buffer ?

Beitrag von martin_frb »

Der canvas muss ja zu irgendeinem component/control gehören. TPanel, oder was du verwendest.

Und der sollte ggf eine Eigenschaft DoubleBuffered haben, die man setzen kann. (Du zeichnest hoffentlich *nur* im paint event?)

Außerdem gibt es ScrollWindowEx das man verwenden kann. (unter gtk2 nur teilweise implementiert, unter gtk1 gas nicht (result := false), carbon und qt weis ich nicht)

pluto
Lazarusforum e. V.
Beiträge: 7192
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: PL Text Engine: Mit Buffer oder ohne Buffer ?

Beitrag von pluto »

Ich leite von TCustomControl ab. Stimmt. Die hat auch sowas... müsste ich mal ausprobieren.
MFG
Michael Springwald

pluto
Lazarusforum e. V.
Beiträge: 7192
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: PL Text Engine: Mit Buffer oder ohne Buffer ?

Beitrag von pluto »

DoubleBuffered habe ich auf True gesetzt. Keine Besserung. Ich muss da wohl noch anders lösen. Ja ich zeichne "nur" in der Paint Mehtode.
Um Zeit zu sparen habe ich sogar:

Code: Alles auswählen

procedure EraseBackground(DC: HDC); override;
    procedure WMEraseBkgnd(var Message: TLMEraseBkgnd); message   LM_ERASEBKGND;
eingefügt, um das neu zeichnen des Hintergrundes zu verhindern. Das ist nämlich nicht Notwendig. Weil ich das schon mache.

Das Scroll läuft zwar Flüssig, aber sobald ich den Slider per Maus Bewege Flackert es. Also müsste ich hier für eine Art Buffer einbauen. Allerdings nur einen der so groß ist wie der Sichtbare Bereich.
Das Probiere ich als nächstes aus. D.H.:
ich erstelle einmal eine TBitMap Variable und weise ihn bei zuweisung einer Größe die jeweilige Client Größe zu. Dann zeichne ich zunächst hier rein, und zeichne dann diese TBitMap komplett auf dem Bildschirm.
MFG
Michael Springwald

pluto
Lazarusforum e. V.
Beiträge: 7192
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: PL Text Engine: Mit Buffer oder ohne Buffer ?

Beitrag von pluto »

Mir ist noch eine etwas andere Lösung eingefallen:
Statt jetzt jedem Objekt einen intern Buffer in Form von einer TBitMap Variable zu geben, habe ich jedem Container einen Intern Grafik Buffer geben. Damit schlage ich gleiche Vier Fliegen mit einer Klappe:
01) Objekte werden Automatisch abgeschnitten und werden nicht über den Zeichen Bereich drüber gezeichnet
02) Beim Verschieben des Sliders mit der Maus, flackert es nicht mehr.
03) Als spätere Optimierung, könnte ich das so machen, dass der Buffer nicht immer verwendet wird, sondern nur dann wenn gescroltl werden soll bzw. wenn die Scorlleisten eingeblendet werden.
04) Jede Position innerhalb eines Container's ist ab zu fort Relativ und nicht mehr Absolut. Da jeder Container bei 0,0 Anfängt.

Diese Lösung ist für mich OK. Denn Container werden nicht so häufig verwendet wir normale Objekte. Daher ist es nur eine Minimale mehr Belastung des Speichers. Theoretisch. Zwar ist auch jeder Absatz ein Container, aber der Buffer ist erst in der zweiten bases Klasse von den Containern, d.h. der Absatz ist im Moment vom ersten Bases Container abgeleitet.
Daher ist das so glaube ich auch die beste Lösung. Wenn ihr noch andere Vorschläge habt, nur her damit. Wenn ich sie verstehe und für mich umsetzbar sind, werde ich es versuchen.

Damit ist meine Frage beantwortet. Die Antwort lautet: Ja mit Buffer !
MFG
Michael Springwald

pluto
Lazarusforum e. V.
Beiträge: 7192
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: PL Text Engine: Mit Buffer oder ohne Buffer ?

Beitrag von pluto »

Seit einiger Zeit habe ich das Problem, dass das Vergrößern der Anwendung recht viel Zeit Inanspruchnahme nimmt.
Meine Nachforschungen haben ergeben das es an "Buffer.Widht" liegt.

Im Soruce-Code von TCustomBitmap, davon ist Indirekt TBitmap abgeleitet finde ich auch in der Methode SetSize den Grund:

Code: Alles auswählen

procedure TCustomBitmap.SetSize(AWidth, AHeight: integer);
var
  SCB: TSharedCustomBitmap;
  CurIntfImage, NewIntfImage: TLazIntfImage;
  NewRawImage: TRawImage;
begin
  RawImageNeeded(True);
 
  if AWidth < 0 then AWidth := 0;
  if AHeight < 0 then AHeight := 0;
 
  SCB := TSharedCustomBitmap(FSharedImage);
  if  (SCB.FImage.Description.Height = cardinal(AHeight))
  and (SCB.FImage.Description.Width = cardinal(AWidth))
  then Exit;
 
  UnshareImage(False);
  // FSHaredImage might have been changed by UnshareImage
  SCB := TSharedCustomBitmap(FSharedImage);
 
  // for delphi compatibility copy old image
  RawImageNeeded(False);
  if  (SCB.FImage.Description.Height >= cardinal(AHeight))
  and (SCB.FImage.Description.Width >= cardinal(AWidth))
  then begin
    // use the faster ExtractRect. Since it calculates the intersection of source
    // and requested rect we can only use it when shrinking the image.
    SCB.FImage.ExtractRect(Rect(0, 0, AWidth, AHeight), NewRawImage);
  end
  else begin
    // use slow copy of pixeldata till rawimage can also copy to larger destination
 
    NewRawImage.Description := SCB.FImage.Description;
    NewRawImage.Description.Width := AWidth;
    NewRawImage.Description.Height := AHeight;
    NewRawImage.ReleaseData;
 
    if SCB.FImage.DataSize > 0 then
    begin
      NewRawImage.CreateData(True);
      CurIntfImage := TLazIntfImage.Create(SCB.FImage, False);
      NewIntfImage := TLazIntfImage.Create(NewRawImage, False);
      NewIntfImage.CopyPixels(CurIntfImage);
      CurIntfImage.Free;
      NewIntfImage.Free;
    end;
  end;
 
  SCB.FImage.FreeData;
  SCB.FImage := NewRawImage;
  // size was changed => update HDC and HBITMAP
  FreeCanvasContext;
  SCB.FreeHandle;
  FreeMaskHandle;
  Changed(Self);
end;
Das Passiert alles bei einer Größen Änderung. Nun meine Preis Frage gibt es etwas anders das ich nutzen könnte für den Intern Buffer ?
Im IRC sagte mir einer, dass ich "TLazIntfImage" nutzen könnte. Jedoch komme ich damit nicht zurecht, weil es keinen Hinweise auf einen Canvas gibt.
Das HTML Panel nutzt allerdings auch einen InternBuffer. Jedoch ganz trikreich:

Code: Alles auswählen

if UsePaintBuffer then begin
    if (PaintBuffer = nil)
    or (PaintBufferBitmap.Width <> Clientrect.Right)
    or (PaintBufferBitmap.Height <> ClientRect.Bottom) then begin
      PaintBufferBitmap.Free;
      PaintBufferBitmap := TBitmap.Create;
      PaintBufferBitmap.Width := ClientRect.Right;
      PaintBufferBitmap.Height := ClientRect.Bottom;
      PaintBuffer := PaintBufferBitmap.Canvas;
    end;
    FTarget := PaintBuffer;
  end else begin
    PaintBuffer := TargetCanvas;
    FTarget := TargetCanvas;
  end;
Zufinden ist der Abschnitt in der Methode: "TIpHtml.Render" in der Unit: "IPHTML.PAS"
Hier meine ich jedoch das es mehr Zeit kosten das immer er PaintBufferBitmap freizugeben und neu zu erstellen, selbst wenn das nur einmal passieren würde.

Hättet ihr Vorschläge ?
MFG
Michael Springwald

pluto
Lazarusforum e. V.
Beiträge: 7192
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: PL Text Engine: Mit Buffer oder ohne Buffer ?

Beitrag von pluto »

Ich mache das jetzt so wie es das HTML Panel macht: Der Interne Buffer wird bei mir jetzt nur noch für das Scrollen genutzt, naja fast. Das hat die Geschwindigkeit drastisch erhöht beim Vergrößern:

Code: Alles auswählen

procedure TPLTE_Container_Default.Paint;
var
  i:Integer;
  c:TCanvas;
  r,r2,r3:TRect;
begin
  if ScrollRect.Top > 0 then
    sy:=top-ScrollRect.Top
  else begin
    if Assigned(Parent) then begin
      sy:=Top-parent.ScrollRect.Top;
    end
    else
      sy:=0;
  end;
 
  if ScrollRect.Left > 0 then
    sx:=Left-ScrollRect.Left
  else begin
    if Assigned(Parent) then begin
      sx:=Left-parent.ScrollRect.Left;
    end
    else
      sx:=0;
  end;
 
  if (Assigned(Parent)) or (isScroll) then begin
    if (Assigned(Parent)) or (buffer.Width <> DOCW) or (Buffer.Height <> DOCH) then begin
      buffer.Width:=DocW;
      buffer.Height:=DocH+5;
    end;
    c:=buffer.Canvas
  end
  else
    c:=Canvas;
 
  Style.ToCanvas(c); c.FillRect(0,0,ClientWidth+5,ClientHeight);
 
  r.Left:=ScrollRect.Left; r.Top:=ScrollRect.Top; r.Right:=R.Left+ScrollRect.Right; r.Bottom:=R.Top+ScrollRect.Bottom;
  for i:=0 to Count-1 do begin
    r3.Left:=items[i].Left; r3.Top:=items[i].Top; r3.Right:=R3.Left+items[i].Width; r3.Bottom:=R3.Top+items[i].Height;
//  if IntersectRect(R2, r,r3) then begin
      if not (Items[i] is TPLTE_Container_Default) then Items[i].ScrollRect:=ScrollRect;
      items[i].Canvas:=c;
      Items[i].Paint;
//    end;
  end;
 
 
  if (Assigned(Parent)) or (isScroll) then begin
    if not Assigned(Parent) then
      Canvas.Draw(0,0,buffer)
    else begin
      Canvas.Draw(sx,sy,buffer)
    end;
    isScroll:=False;
  end;
 
end; // TPLTE_Container_Default.Pain
Wegen der Verbschachtelung musste ich eine "Ausnahme" einfügen.
MFG
Michael Springwald

pluto
Lazarusforum e. V.
Beiträge: 7192
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: PL Text Engine: Mit Buffer oder ohne Buffer ?

Beitrag von pluto »

So geht das zwar schon recht gut, aber zufrieden bin ich damit noch nicht !

Gibt es eine Möglichkeit etwas "Schenllers" als TBitmap zuverwenden ?
Wenn ich ein Fenster vergrößere Dauert das ja auch keine halbeewigkeit. Leider kann ich bei einem Canvas auch die Größe nicht direkt setzten. Ich bin noch nicht wirklich dahinter gekommen wie das bei LCL-Komponenten gemacht wird, die über ein Canvas verfügen.
MFG
Michael Springwald

monta
Lazarusforum e. V.
Beiträge: 2809
Registriert: Sa 9. Sep 2006, 18:05
OS, Lazarus, FPC: Linux (L trunk FPC trunk)
CPU-Target: 64Bit
Wohnort: Dresden
Kontaktdaten:

Re: PL Text Engine: Mit Buffer oder ohne Buffer ?

Beitrag von monta »

Gibt es auch die Möglichkeit, die Fragen zur Abwechslung auch lesbar, kurz und verständlich zu formulieren, ohne immer in Seitenlange Monologe zu verfallen?
Johannes

pluto
Lazarusforum e. V.
Beiträge: 7192
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Re: PL Text Engine: Mit Buffer oder ohne Buffer ?

Beitrag von pluto »

kurz und verständlich zu formulieren, ohne immer in Seitenlange Monologe zu verfallen?
Das ist leider recht schwierig. Ich versuche immer so ausführlich wie nur möglich zu Fragen.

Ich versuch es mal: Ich möchte nicht TBitMap verwenden weil mir das zu langsam ist. Daher möchte ich was anders nehmen. Ich möchte ja nur den Canvas Verwenden.
PS: Allerdings habe ich es gestern geschafft ganz ohne Buffer auszukommen bei der Verschachtelung. Ich weiß nicht wie das z.b. ein TCustomControll schafft den Canvas zu Vergrößern.
MFG
Michael Springwald

Antworten