Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Cross-Platform-Entwicklung (https://www.delphipraxis.net/91-cross-platform-entwicklung/)
-   -   iOS Multithreaded Zeichnen (https://www.delphipraxis.net/196934-multithreaded-zeichnen.html)

Sherlock 2. Jul 2018 08:00

Multithreaded Zeichnen
 
Ich versuche die Zeit zu verkürzen, die meine Applikation einfriert, wenn ich zeichne. Da ab Tokyo Bitmaps threadsicher sein sollen, habe ich das zeichnen auf die Bitmap in einen Thread ausgelagert und möchte die fertige Bitmap per Synchonize an die GUI übergeben. Unter Windows klappt das einwandfrei, mit dem iOS Simulator ebenso. Auf dem iDevice hingegen gar nicht. Ich habe dazu ein kleines Testprojekt gebaut, daß in per Button einen Thread startet, der auf einer Bitmap tausend zufällige Punkte mit einer Linie verbindet und dann das Ergebnis in ein Image auf der Oberfläche setzt. Das habe ich probiert per direkter Zuweisung, per Assign und CopyFromBitmap. Nichts führte zu einem sichtbaren Ergebnis.

Hier die relevanten Methoden:
Delphi-Quellcode:
procedure TPainter.Execute;
var
  myPoint1 : TPoint;
  myPoint2 : TPoint;
  i       : integer;
  service : IFMXPhotoLibrary;
begin
  inherited;
  while not Terminated do
  begin
    myPoint1 := TPoint.Zero;
    if fBMP.Canvas.BeginScene then
    begin
      fBMP.Canvas.Clear(TAlphaColorRec.Null);
      fBMP.Canvas.Stroke.Thickness := 1;
      fBMP.Canvas.Stroke.Color := TAlphaColorRec.Black;
      try
        for i := 0 to 1000 do
        begin
          myPoint2 := TPoint.Create(Random(fBMP.Width), Random(fBMP.Height));
          fBMP.Canvas.DrawLine(myPoint1, myPoint2, 1);
          myPoint1 := myPoint2;
        end;
      finally
        fBMP.Canvas.EndScene;
      end;
    end;
    Synchronize(updateGui);
    Sleep(1000);
  end;
end;
Und die synchronisierte Methode:
Delphi-Quellcode:
procedure TPainter.updateGui;
begin
  Form16.Image1.BeginUpdate;
  Form16.Image1.Bitmap.SetSize(fBMP.Size);
  Form16.Image1.Bitmap.Assign(fBMP);
  Form16.Image1.EndUpdate;
  Form16.Image1.Repaint;
end;
Im Ergebnis sollte eine Bitmap mit wildem Zickzack einmal pro Sekunde neu gezeichnet werden.

Was mache ich falsch?

TiGü 2. Jul 2018 09:11

AW: Multithreaded Zeichnen
 
Mangels iOS-Gerät kann ich es nicht testen und der folgende Quelltext ist nur ein Schuss ins Blaue, aber du kannst es ja mal versuchen.

Wesentliche Änderungen:

1. Erzeugung des Thread-Bitmaps im Execute und damit im Thread-Kontext (fühlt sich richtiger an - ob in FMX notwendig wissen andere besser).
2. Benachrichtigung der GUI durch übergebende Callback (flexibler, kein Zugriff auf globale Variablen [ja, ich weiß es es nur ein Testprojekt]).
3. Lesen und schreiben zwischen den Bitmaps mithilfe der Map-Methode und TBitmapData.Copy.

Vielleicht ist Punkt Nummer Drei die Lösung. Versuch macht klug!

Delphi-Quellcode:
unit ThreadBitmap.View;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Controls.Presentation, FMX.StdCtrls, FMX.Objects;

type
  TUpdateGui = TProc<TBitmap>;
 
  TPainter = class(TThread)
  private
    fBMP: TBitmap;
    fUpdateGui: TUpdateGui;
    procedure DoPainting(const ACanvas: TCanvas; const AWitdh, AHeight: Integer);
    procedure updateGui;
    procedure DoUpdateGui;

  protected
    procedure Execute; override;
  public
    constructor Create(const AUpdateGui: TUpdateGui);
    destructor Destroy; override;

  end;

  TForm16 = class(TForm)
    Image1: TImage;
    Button1: TButton;
    procedure FormDestroy(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    FPainter: TPainter;
    procedure updateGui(ABitmap: TBitmap);
  public
    { Public declarations }
  end;

var
  Form16: TForm16;

implementation

{$R *.fmx}

{ TPainter }

constructor TPainter.Create(const AUpdateGui: TUpdateGui);
begin
  fUpdateGui := AUpdateGui;
  inherited Create(false);
end;

destructor TPainter.Destroy;
begin
  fUpdateGui := nil;
  inherited;
end;

procedure TPainter.DoPainting(const ACanvas: TCanvas; const AWitdh, AHeight: Integer);
var
  myPoint1: TPoint;
  myPoint2: TPoint;
  I: Integer;
begin
  myPoint1 := TPoint.Zero;
  if ACanvas.BeginScene then
  begin
    ACanvas.Clear(TAlphaColorRec.Null);
    ACanvas.Stroke.Thickness := 1;
    ACanvas.Stroke.Color := TAlphaColorRec.Black;
    try
      for I := 0 to 1000 - 1 do
      begin
        myPoint2 := TPoint.Create(Random(AWitdh), Random(AHeight));
        ACanvas.DrawLine(myPoint1, myPoint2, 1);
        myPoint1 := myPoint2;
      end;
    finally
      ACanvas.EndScene;
    end;
  end;
end;

procedure TPainter.Execute;
begin
  inherited;
  fBMP := TBitmap.Create(256, 256);
  try
    while not Terminated do
    begin
      DoPainting(fBMP.Canvas, fBMP.Width, fBMP.Height);
      updateGui;
      if not Terminated then
        Sleep(1000);
    end;
  finally
    fBMP.Free;
  end;
end;

procedure TPainter.DoUpdateGui;
begin
  fUpdateGui(fBMP);
end;

procedure TPainter.updateGui;
begin
  if Assigned(fUpdateGui) then
  begin
    Synchronize(DoUpdateGui);
  end;
end;

procedure TForm16.FormDestroy(Sender: TObject);
begin
  if Assigned(FPainter) then
    FPainter.Free;
end;

procedure TForm16.FormCreate(Sender: TObject);
begin
  FPainter := nil;
end;

procedure TForm16.Button1Click(Sender: TObject);
begin
  FPainter := TPainter.Create(updateGui);
end;

procedure TForm16.updateGui(ABitmap: TBitmap);
var
  LBitmap: TBitmap;
  LDataWrite, LDataRead: TBitmapData;
begin
  // Self.Image1.BeginUpdate;
  // try
  // Self.Image1.Bitmap.SetSize(ABitmap.Size);
  // Self.Image1.Bitmap.Assign(ABitmap);
  // finally
  // Self.Image1.EndUpdate;
  // Self.Image1.Repaint;
  // end;

  Self.Image1.BeginUpdate;
  try
    LBitmap := Self.Image1.Bitmap;
    LBitmap.SetSize(ABitmap.Size);
    if LBitmap.Map(TMapAccess.Write, LDataWrite) and ABitmap.Map(TMapAccess.Read, LDataRead) then
    begin
      try
        LDataWrite.Copy(LDataRead);
      finally
        ABitmap.Unmap(LDataRead);
        LBitmap.Unmap(LDataWrite);
      end;
    end;
  finally
    Self.Image1.EndUpdate;
    Self.Image1.Repaint;
  end;
end;

end.

Rollo62 2. Jul 2018 09:31

AW: Multithreaded Zeichnen
 
Schliesse mich TiGü an ...

Aber hast du schonmal versucht statt
Delphi-Quellcode:
Synchronize(updateGui);
die TThread-Funktionen zu nehmen ?
Kann gerade nicht nachschauen, womöglich verbirgt sich hinter Synchrinose genau dasselbe ...

Delphi-Quellcode:
TThread.Synchronize(nil,
                    procedure
                        updateGui;
                    end);
Edit: Queue funktioniert hier wohl nicht ....
oder
Delphi-Quellcode:
TThread.Queue(nil,
              procedure
                  updateGui;
              end);

Aber ganz ehrlich, nur weil EMBA schreibt TBitmap wäre threadsicher muss das nicht stimmen.
Ich fände das auch recht spannend.

Falls das Beispiel von TiGü bei dir läuft werde ich das mal auf iOS Testen, aber ich komme wahrscheinloch erst am Mittwoch dazu.

Rollo

Sherlock 2. Jul 2018 09:45

AW: Multithreaded Zeichnen
 
Also, TiGüs Variante funktioniert genausowenig. Parallel kann ich noch sagen, daß es unter macOS ebenso funktioniert.

Der Punkt ist vermutlich nicht das wie die Methode zum Updaten des Image mit der gezeichneten Bitmap aufzurufen ist, sondern ob die Methode selbst so korrekt ist, bzw. den Ansprüchen von iOS genügt.

Sherlock

Rollo62 2. Jul 2018 09:53

AW: Multithreaded Zeichnen
 
Ich habe mir das noch nicht angeschaut, aber es müsste ja in Allen Platformen threadsicher sein.
Das wäre doch ein großer Sprung, das wird womöglich erst in enem späteren Update kommen.

Dies ist jetzt auch der erste Versuch wo das mal jemand austested, soweit ich sagen kann :stupid:

Rollo

TiGü 2. Jul 2018 09:58

AW: Multithreaded Zeichnen
 
Zitat:

Zitat von Sherlock (Beitrag 1406280)
Also, TiGüs Variante funktioniert genausowenig. Parallel kann ich noch sagen, daß es unter macOS ebenso funktioniert.

Der Punkt ist vermutlich nicht das wie die Methode zum Updaten des Image mit der gezeichneten Bitmap aufzurufen ist, sondern ob die Methode selbst so korrekt ist, bzw. den Ansprüchen von iOS genügt.

Sherlock

Interessant wäre, ob das Map und Copy von TBitmapData erfolgreich durchlaufen wird oder fehlschlägt.
Oder irgendwas davor. Der Canvas für iOS ist welcher Art? OpenGL?

Sherlock 2. Jul 2018 10:16

AW: Multithreaded Zeichnen
 
FMX ist nach meinem Verständnis abgesehen von Windows immer OpenGL.

Die Durchläufe sind erfolgreich. Ich kann zB einen Zähler am Ende erhöhen, und dessen Wert in einem Label anzeigen lassen.

Sherlock

Rollo62 2. Jul 2018 18:49

AW: Multithreaded Zeichnen
 
Ich habe damit mal ein bischen rumgespeilt, mit TCriticalSectios, Events, etc.
Auch mit mehreren Teil-Bildern wenn ich die Bilder von mehreren Paintern vorbereite, und dann das Ergebnis per Timer abhole.

Es verhält sich auf Allen Platformen anders, auf OSX und IOS kann es mal Laufen, aber auf Android habe ich es nicht hinbekommen.

Ich vermute mal es liegt am TImage, auch BeginUpdate und Image.Canvas.BeginScene hilft nicht viel.

Vieleicht muss man das besser über ein Bitmap im Hintergrund machen, und da dan dem Image.Bitmap zuweisen.

Es gibt viele Wege, aber Alles hat Vor- und Nachteile, und ist anscheinend recht lahm.
Wäre schön wenn EMBA mal ein Demo dazu rausgeben würden, bei dem die Performance optimal bleibt.

Ansonsten ist das vielleicht ein Ansatz, von Eugene Kryukov, um das Zeichnen von Teilbereichen zu beschleunigen.
Funktioniert bei mir ganz gut, setze ich aber noch nicht produktiv ein.

Edit:
Und GetPixel statt Copy macht auch einen Unterschiede, damit geht es zuverlässiger (aber natürlich langsamer).
Delphi-Quellcode:
                for y := 0 to LDataRead.Height-1 do
                  for x := 0 to LDataRead.Width-1  do
                  begin
                      LDataWrite.SetPixel( x + LOfsX, y + LOfsY, LDataRead.GetPixel( x, y) );
                  end;

// statt               LDataWrite.Copy(LDataRead);
Rollo

EWeiss 2. Jul 2018 20:02

AW: Multithreaded Zeichnen
 
Zitat:

Queue funktioniert hier wohl nicht ....
Ist mir unverständlich warum es nicht gehen sollte.
Ist doch letztendlich nichts anderes als PostMessage!

Kenne mich zwar mit OpenGL aus aber mit FMX habe ich mich nicht beschäftigt da ich das Umfeld nicht habe.

gruss

Harry Stahl 2. Jul 2018 23:54

AW: Multithreaded Zeichnen
 
Zitat:

Zitat von Sherlock (Beitrag 1406269)
Ich versuche die Zeit zu verkürzen, die meine Applikation einfriert, wenn ich zeichne. Da ab Tokyo Bitmaps threadsicher sein sollen, habe ich das zeichnen auf die Bitmap in einen Thread ausgelagert und möchte die fertige Bitmap per Synchonize an die GUI übergeben.

Im Ergebnis sollte eine Bitmap mit wildem Zickzack einmal pro Sekunde neu gezeichnet werden.

Was mache ich falsch?

Ich habe im Moment leider kein IOS-Gerät im Entwicklungs-Einsatz, kann daher meinen Vorschlag nicht selber testen, muss ich Dir also überlassen.
Deine Variante funktioniert jedenfalls auf einem Android-Device, könnte also ggflls. auch ein spezielles IOS-Problem sein.

"Threadsicher" heißt ab 10.2, dass die Zugriffe mehrerer Threads auf einen Canvas intern von Delphi serialisiert werden. Damit hat sich auch die Art, wann man ein Locking vornimmt, etwas geändert, da bei Dir aber nicht mehrere Threads an einer Grafik arbeiten und Du ja gewollt eine Pause von 1 Sekunde haben willst, ist das hier egal (mehr Infos hierzu bei Bedarf in meinem aktuellen FMX-Buch im Grafik-Kapitel unter 6.4).

Diese Änderung hat aber letztlich auch zur Konsequenz, dass Du das temporäre Bitmap gar nicht mehr brauchst, sondern direkt Image1.bitmap zum zeichnen verwenden kannst (eine extra Synchronisierung entfällt also). Damit sollte auch das Zuweisungsproblem von fBMp an Image1.bitmap entfallen, das aus irgendeinem Grund anscheinend nicht unter IOS funktioniert (wäre zwar ein "umgehen" des Problems, aber eine Lösung, die man mal versuchen könnte, ist ja nicht mehr als copy und paste):

Schlage also mal vor zu testen, ob es so auch auf Deinem IOS-Device funktioniert(unter Windows, Linux, Android geht es):

Delphi-Quellcode:
procedure TPainter.Execute;
var
  myPoint1 : TPoint;
  myPoint2 : TPoint;
  i : integer;
begin
  inherited;
  while not Terminated do
  begin
    myPoint1 := TPoint.Zero;
    if Form15.Image1.bitmap.Canvas.BeginScene then
    begin
      Form15.Image1.bitmap.Canvas.Clear(TAlphaColorRec.Null);
      Form15.Image1.bitmap.Canvas.Stroke.Thickness := 1;
      Form15.Image1.bitmap.Canvas.Stroke.Color := TAlphaColorRec.Black;
      try
        for i := 0 to 1000 do
        begin
          myPoint2 := TPoint.Create(Random(Form15.Image1.Bitmap.Width), Random(Form15.Image1.bitmap.Height));
          Form15.Image1.bitmap.Canvas.DrawLine(myPoint1, myPoint2, 1);
          myPoint1 := myPoint2;
        end;
      finally
        Form15.Image1.bitmap.Canvas.EndScene;
      end;
    end;
    //Synchronize(updateGui); // wird nicht benötigt
    Sleep(1000);
  end;
end;
Image1.bitmap muss irgendwo natürlich noch mit einer sinnvollen Größe vorbelegt werden.

Rollo62 3. Jul 2018 10:36

AW: Multithreaded Zeichnen
 
Hallo Harry,

ja richtig, in Canvas.BeginScene wird ein Lock gemacht.
Win, OSX, Android funktionieren bei mir auch (nur das Android anscheinend etwas falsch skaliert,
aber das sit ein anderes Thema).
iOS geht bei mir damit leider auch nicht.

Mir ging es darum das mehrere Threads auf einem Bitmap schreiben können, das hatte ich probiert
mit 4 TPainter Klassen, die dann aber beim Schreiben gegenseitig aufeinander Warten müssen.
Funktioniert hat das schon, aber die 4 Painter haben sich ziemlich behindert gegenseitig.
Hatte aber noch externes Lock ausprobiert, mit dem BeginScene Lock hat sich das womöglich überschnitten.

Ich probiere noch ein bischen damit rum.

Rollo

Rollo62 3. Jul 2018 11:29

AW: Multithreaded Zeichnen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hab mal ein Testprojekt drangehangen.
Basierend auf der Vorlage von TiGü habe ich das etwas erweitert und "buntisiert" (weil hübscher als schwarz/weiss) :stupid:

Läuft auf Win mit 4 TPainter-Threads, und dem Vorschlag von Harry immer direkt auf dem Image zu zeichnen.
Win Sample ist so wie gedacht: 4x Taste Drücken 4 separate Bereiche werden gemalt.

Schon OSX hat falsche Skalierungen (finde jetzt nicht so schnell den Fehler), und malt immer
im ganzen Bild statt in einem der 4 Teilbilder.

Android genauso falsch skaliert.

iOS malt im Moment gar nicht, habe ich bei mir bisher auch nicht hinbekommen.
Ich kann aber mit iOS zeichnen, das mache ich auch, ich muss mal checken wo jetzt genau das Problem sein könnte, habe aber gerade keine Zeit mehr dafür.


Rollo

Rollo62 3. Jul 2018 18:56

AW: Multithreaded Zeichnen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hab noch ein bischen rumgespielt ...

Ich erzeuge 4 Teilbitmps in Threads, diese werden dan in einem Taeget Bitmap zusammengebaut.
Wenn Alle Threads fertig sind wird das komplette Target in das Image geschrieben, mit
Delphi-Quellcode:
procedure DoDrawBitmap(const ACanvasDst : TCanvas;
                       const ADstRc    : TRectF;
                       const ASrcBmp   : TBitmap);
var
  LDstRc: TRectF;
begin
    if ACanvasDst.BeginScene then
        try
            LDstRc := RectF(0, 0, ADstRc.Width, ADstRc.Width);
            LDstRc.Offset( ADstRc.TopLeft );


            ACanvasDst.DrawBitmap(ASrcBmp, // Src bmp full
                                  RectF(0,0, ASrcBmp.Width, ASrcBmp.Height), // Src rc full
                                  LDstRc, // dst part bmp to dst canvas
                                  1);

        finally
            ACanvasDst.EndScene;
        end;

end;
Wird das Teil-Bmp in das Tgt-Bmp geschrieben.

Funktioniert auf Win, OSX, And, aber noch nicht auf iOS :(

Sorry, der Code ist noch ein bischen wüst, durch die ganzen Tests, ich hoffe das erkennt man noch wieder :stupid:
Ob es jetzt Threadmäßig optimal ist wage ich auch zu bezweifeln, mit ging es erstmal drum das
Scaling und Printing überhaupt funktioniert.
Die Performance ist bei mit jedenfalls im Bereich 60-160FPS, je nach Plattform.

Aber wie man das auf eine optimale Performance bringt, vor Allem auch auf allen Platformen, ist noch nicht klar.

Womöglich mit TScene von Eugene, der Teilbereiche bei dem Bildupdate berücksichtigt, während FMX immer das ganze Bild updated.
Vielleicht hat ja noch jemand Ideen dazu.


Rollo

bytecook 3. Jul 2018 22:46

AW: Multithreaded Zeichnen
 
Hi Leute,

das hat zwar nichts mit IOS zu tun, jedoch mit multithreaded painting sowie mit teilweiser Aktualisierung...
Im Graphics32 Framework findet sich ein schöner Lösungsansatz zu Multithreaded 'Zeichnen', einfach mal so als Grundlage / Anregung.
Siehe TSyntheticImage in GR32_ExtImage.pas
https://graphics32.github.io/Docs/Un...mage/_Body.htm

Rollo62 4. Jul 2018 06:30

AW: Multithreaded Zeichnen
 
Hallo bytecook,

ja gute Idee, GR32 für FMX wollte ich schon immer mal Testen.
GR32 war schon immer eine super Lösung

Habe es mir nicht angesehen, aber ich vermute mal da wird noch ein Grafiklayer über den FMX-Layer gelegt.
Macht das wirklich Sinn, und wird das GR32 durch GPU unterstützt ?

Sollte man mal checken, ich kann aber erst nächste Woche weitertesten.

Rollo

Sherlock 4. Jul 2018 06:59

AW: Multithreaded Zeichnen
 
Liebe Mitstreiter, das ist alles ganz dufte, aber so wie es aussieht, nix für iOS. :pale:

Vermutlich muss wirklich im Mainthread gemalt werden, was für Applikationen, die viel Malen und dennoch nicht einfrieren sollen, nicht so ganz das gelbe vom Ei ist. Ich hänge an der Sache seit knapp einem Jahr. Es sieht langsam so aus, als müßte ich mich in Swift einlesen. :roll:

Danke jedenfalls für Eure Unterstützung!

Sherlock

TiGü 4. Jul 2018 08:31

AW: Multithreaded Zeichnen
 
Zitat:

Zitat von Sherlock (Beitrag 1406468)
Liebe Mitstreiter, das ist alles ganz dufte, aber so wie es aussieht, nix für iOS. :pale:

Vermutlich muss wirklich im Mainthread gemalt werden, was für Applikationen, die viel Malen und dennoch nicht einfrieren sollen, nicht so ganz das gelbe vom Ei ist. Ich hänge an der Sache seit knapp einem Jahr. Es sieht langsam so aus, als müßte ich mich in Swift einlesen. :roll:

Besteht die Möglichkeit auf den Gerät in die verwendete Canvas-Klasse zu debuggen?
Es gibt in FMX.Canvas.Mac ja einen TCanvasQuartz.
Wird der verwendetet?

Was mir noch eingefallen ist:
Kannst du prüfen, ob das Quell- und Ziel-Bitmap das exakt gleiche Farbformat haben?
Vielleicht schlägt das Ganze ja fehl, weil ein Bitmap im Thread bspw. irgendein anderes Farbformat hat (ARGB vs. BGRA vs. RGBA) als ein Bitmap eines TImage.

Sherlock 4. Jul 2018 09:03

AW: Multithreaded Zeichnen
 
Man kann derzeit (ist es wirklich schon ein Jahr?) mit Delphi nicht mehr on iDevice debuggen. Und im Simulator läuft alles total dufte und erwartungskonform.

Sherlock

Sherlock 4. Jul 2018 12:57

AW: Multithreaded Zeichnen
 
Äh, hier ein kleines Update (es hat mir keine Ruhe gelassen): Wenn man das Bitmap vor dem
Delphi-Quellcode:
Synchronize(UpdateGUI)
Aufruf in meiner ursprünglichen Painter.Execute Methode speichert, dann wird es auch auf der Oberfläche angezeigt. :shock:

Ich verstehe aktuell noch nicht den Zusammenhang, vermute allerdings, daß iOS einfach erst beim Speichern merkt, daß ich es ernst meine mit dem zeichnen, und dann alles, was bisher "virtuell" statt fand "realisiert".

Jedenfalls kann ich jetzt versuchen darauf aufzubauen, das speichern kostet quasi Null Zeit, bzw geht in meinen sonstigen Unternehmungen, um die Bitmap zu füllen, unter.

Sherlock

Sherlock 4. Jul 2018 13:50

AW: Multithreaded Zeichnen
 
So, noch eine Stunde später, noch eine Erkenntnis:
Die TBitmap.SaveToFile Methode macht etwas (für mich) unerwartetes. Die Bitmap wird auf einem TSurfaceBitmap assigned, und erst das wird dann gespeichert. Was genau eine TSurfaceBitmap ist, kann ich mangels Doku nicht sagen, aber wenn ich statt der Speichermethode diesen hohlen Dreizeiler ausführe:
Delphi-Quellcode:
      surf := TBitmapSurface.Create;
      surf.Assign(fBMP);
      surf.Free;
Dann wird die Bitmap immer korrekt angezeigt (TBitmapSurface benötigt FMX.Surfaces).

Mag das einer erklären :?:

Sherlock

Rollo62 4. Jul 2018 16:18

AW: Multithreaded Zeichnen
 
Zitat:

Man kann derzeit (ist es wirklich schon ein Jahr?) mit Delphi nicht mehr on iDevice debuggen.
Also ich debugge mit Rx10.2.2 XCode9.2, iOS10.2.6 und MacOS10.13.5 wieder, aber noch traue ich
mich nicht auf die letzten Stände upzudaten, weil im Moment Alles so gut läuft.

TBitmapSurface:
Ja das könnte eine Möglichkeit sein, ich hatte über ide Jahre mehrere Versuche mit LoadFromFile/Stream, und setze da auch BitmapSurface ein.
Insbesondere im Zusammenhang mit TBitmapCodecManager war das ein gutes Team.
Durch das viele Rumprobiere und Hin- und Her kann ich leider nicht mehr genau sagen warum.

Kann gut sein das BMS auch hier die Lösung ist, kann ich im Moment aber nicht checken.

Rollo

Harry Stahl 4. Jul 2018 22:01

AW: Multithreaded Zeichnen
 
Zitat:

Zitat von Sherlock (Beitrag 1406489)
So, noch eine Stunde später, noch eine Erkenntnis:
Die TBitmap.SaveToFile Methode macht etwas (für mich) unerwartetes. Die Bitmap wird auf einem TSurfaceBitmap assigned, und erst das wird dann gespeichert. Was genau eine TSurfaceBitmap ist, kann ich mangels Doku nicht sagen, aber wenn ich statt der Speichermethode diesen hohlen Dreizeiler ausführe:
Delphi-Quellcode:
      surf := TBitmapSurface.Create;
      surf.Assign(fBMP);
      surf.Free;
Dann wird die Bitmap immer korrekt angezeigt (TBitmapSurface benötigt FMX.Surfaces).

Mag das einer erklären :?:

Sherlock

Das TBitmapSurface ist so eine Art einheitliches Datenformat, das als Transferschnittstelle mit dem Bitmap-Codec-Manager zusammenarbeitet, um das Speicherbitmap in eine Datei oder einen Stream zu speichern oder zu lesen.

Warum die Aktionen, die beim surf.assign (fmbp) stattfinden, zur anschließenden Aktualisierung führen, kann ich mangels Testmöglichkeit nur vermuten, ich würde eine gewisse Möglichkeit bei "TMonitor.Enter", bzw. letztlich bei "TMonitor.Exit" sehen, da hier bestimmte Benachrichtigungen ans System übermittelt werden.

Versuch doch einfach mal nur mit TMonitor.enter (fbmp) und TMonitor.exit (fbmp).

Sherlock 5. Jul 2018 15:15

AW: Multithreaded Zeichnen
 
Zitat:

Zitat von Harry Stahl (Beitrag 1406516)
Versuch doch einfach mal nur mit TMonitor.enter (fbmp) und TMonitor.exit (fbmp).

Nach dem (langen) Wochenende. Danke!

Sherlock

Sherlock 10. Jul 2018 09:36

AW: Multithreaded Zeichnen
 
Nein, leider bringt TMonitor.Enter und TMonitor.Exit nicht das gleiche Ergebnis wie der TSurfaceBitmap Unfug.

:|

Sherlock


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:42 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz