![]() |
FMX-TBitmap: Nach Gebrauch von Canvas ins threads unbrauchbar?
Liste der Anhänge anzeigen (Anzahl: 1)
Eigentlich sollten Pixel-Manipulationen mit TBitmapData doch thread-safe sein. Jedenfalls sind sie das meiner Erfahrung nach, aber nur, wenn man mit Bildern arbeitet, die von der Festplatte geladen werden oder in TImageControls gespeichert sind.
Sowie man eine Bitmap per Canvas-Operationen verändert hat, ob im Haupt-Thread oder im Hintergrund, bekommt man Probleme, jedenfalls mit Delphi 10.3.3, und besonders unter Android, wo man doch gerade da darauf angewiesen ist, lange Operationen im Hintergrund auszuführen. Wenn ich meine Videos nicht im Hintergrund schreiben kann, ist das Cross-Platform-Projekt dafür gelaufen. Ich hab ein Testprojekt gemacht, in dem Bitmaps mit und ohne Gebrauch von Canvas im Hintergrund rotiert werden (mit Harry Stahls Rotierer übersetzt nach FMX). Ich hänge es mal an, vielleicht hat jemand Interesse mal zu schauen, was da schief läuft. Hoffentlich durch einen Fehler von mir. Es sieht so aus, als wenn nach Gebrauch vom Canvas das RefCounting durcheinander gerät:?: Besonders schön wäre ja, wenn das alles in 10.4 schon funktioniert. Danke, Renate |
AW: FMX-TBitmap: Nach Gebrauch von Canvas ins threads unbrauchbar?
Hallo,
in irgend einer Delphi Version, weiß nur gerade nicht welcher, war die Threadsicherheit von FMX TBitmap als Neuheit eingeführt worden. Grüße TurboMagic |
AW: FMX-TBitmap: Nach Gebrauch von Canvas ins threads unbrauchbar?
Ich meine fmx.graphics.tbitmap in Rio gilt offiziell als thread-safe. Konnte gerade auch nichts konkretes dazu finden. Habe jedoch gerade dies auf stackoverflow gefunden:
![]() Gruß, Renate |
AW: FMX-TBitmap: Nach Gebrauch von Canvas ins threads unbrauchbar?
Ich habe versuchsweise FMX.Canvas.D2D für den Privatgebrauch gepatcht mit TMonitors, wie in
![]() Für den Normalgebrauch scheint aber der Trick, nach Benutzung von TBitmap.Canvas die Pixels in eine neue Bitmap zu kopieren und die alte zu (wie übersetzt man free auf deutsch?), jedenfalls dieser Trick funktioniert in Normalsituationen ganz gut. Mein Beispiel ist schlecht gewählt, denn beim wiederholten Rotieren wird dauernd assign für die gleiche BM ausgeführt, und das führt auf die Dauer zu Problemen (hat es jedenfalls früher). Jedenfalls werde ich mal weiter testen, und bin natürlich für Ideen von Euch extrem dankbar :) Renate |
AW: FMX-TBitmap: Nach Gebrauch von Canvas ins threads unbrauchbar?
... freizugeben...
|
AW: FMX-TBitmap: Nach Gebrauch von Canvas ins threads unbrauchbar?
Zitat:
|
AW: FMX-TBitmap: Nach Gebrauch von Canvas ins threads unbrauchbar?
Der Vollständigkeit halber hier die Version, die bei mir bis jetzt verlässlich läuft:
Meine pointer-version der Rotation hat zu dem Problem beigetragen, wieso verstehe ich im Moment nicht, aber das ist ein andere Frage.
Delphi-Quellcode:
var
Form2: TForm2; implementation {$R *.fmx} uses System.threading, System.UIConsts; // Ohne pointers ist es sicherer procedure Rotate(const bm: TBitmap); var x, y, b, h: integer; DataSource, DataTarget: TBitmapData; help: TBitmap; begin b := bm.height; h := bm.width; help := TBitmap.Create; try help.SetSize(b, h); Assert(bm.Map(TMapAccess.ReadWrite, DataSource)); Assert(help.Map(TMapAccess.ReadWrite, DataTarget)); for y := 0 to h - 1 do begin for x := 0 to b - 1 do begin DataTarget.SetPixel(x, y, DataSource.GetPixel(y, b - 1 - x)); end; end; help.Unmap(DataTarget); bm.Unmap(DataSource); bm.Assign(help); finally help.free; end; end; procedure TextOnBitmapSimple(const bm: TBitmap; const text: String; cb, ct: Cardinal); begin bm.Canvas.BeginScene; bm.Canvas.Clear(cb); bm.Canvas.Font.Size := 30; bm.Canvas.Fill.Color := ct; bm.Canvas.FillText(RectF(0, 0, bm.width, bm.height), text, False, 1, [], TTextAlign.Center, TTextAlign.Center); bm.Canvas.EndScene; end; // Ohne die mit // ? markierten Stellen geht der Canvas-Inhalt unter Android verloren procedure TextOnBitmap(const bm: TBitmap; const text: String; cb, ct: Cardinal); var am: TBitmap; begin // ?Im Haupt-Thread ausführen TThread.Synchronize(TThread.Current, procedure begin // ?Den Canvas von einer temporären Bitmap benutzen am := TBitmap.Create; try am.SetSize(bm.width, bm.height); TextOnBitmapSimple(am, text, cb, ct); // ?Pixel rüberkopieren bm.CopyFromBitmap(am); finally am.free; end; end); end; // Gucken was los ist procedure TForm2.ShowProgress(i: integer; const bm: TBitmap); begin TThread.Synchronize(TThread.Current, procedure begin ProgressBar1.Value := i; ImageControl2.Bitmap := bm; // refcount ist immer 3, wieso? Label2.text := IntToStr(bm.Image.refcount); sleep(500); end); end; procedure TForm2.Button5Click(Sender: TObject); var bm: TBitmap; i, count: integer; aThread: TThread; begin ImageControl2.Bitmap := nil; aThread := TThread.CreateAnonymousThread( procedure begin count := trunc(SpinCount.Value); bm := TBitmap.Create; bm.SetSize(600, 400); TextOnBitmap(bm, 'This works', claYellow, claBlue); i := 0; while i < count do begin ShowProgress(i, bm); Rotate(bm); inc(i); end; ShowProgress(count, bm); bm.free; end); aThread.Start; end; |
AW: FMX-TBitmap: Nach Gebrauch von Canvas ins threads unbrauchbar?
Ich hatte Dein ursprüngliches Beispiel mal getestet und kann insofern die Probleme (insbesondere unter Android) bestätigen. Hatte auch festgestellt, dass die Pointer-Drehvariante eher Probleme erzeugt, als die simple Version. Ich hatte dann noch versucht es ein wenig zu optimieren (z.B. potentielle Kollisionen mit entsprechendem Auslassen von Zugriffen auf das Bitmap zu vermeiden, indem ich auf versucht habe, auf entsprechende Rückgaben von Beginsceene oder Map zu reagieren (die liefern ja ein Boolean zurück, ob ein Zugriff möglich ist oder nicht). Auch hatte ich statt Synchronize "Queue" bzw. "ForceQueue" verwendet, um den Eintritt in den Hauptthread ein wenig nach hinten zu verzögern. Ich hatte damit zwar eine "Erfolgsquote" von ca. 60-80% unter Android aber eben nicht 100% und ich konnte nicht wirklich irgendwelche Kollisionen registrieren.
Ich habe leider keine Ahnung wo das Problem genau liegt. Mit Delhi 10.2 kam ja die Information, dass TBitmap, TCanvas und Tcontext 3D threadsicher gemacht worden seien man aber die Zugriffsweise auf diese Ressourcen etwas ändern sollte (hatte ich in meinem Buch für den Zugriff auf TCanvas beschrieben). Die Erläuterung war, dass die Zugriffe intern serialisiert werden und in eine Warteschlange kommen. Wenn ich mir den Code in FMX.Graphics und FMX.Canvas.D2D etc. so ansehe (was sehr schwierig ist, da die entscheidenen Prozeduren virtuelle Prozeduren sind und je nach Plattform oft andere Units aufgerufen werden, man kommt also an den tatsächlichen Ablauf nur ran, wenn man debugt, was aber in einem System, das Event- und Messagebasiert arbeitet auch nicht immer möglich ist), habe ich aber den Eindruck, als ob ein Schutz nur gegeben ist, für mehrere Zugriffe auf TCanvas (Beginscene) oder TBitmap (Content) per Map aber der Mix dererlei Zugriffe eben nicht. Aber das ist eher eine Vermutung, als dass ich es wirklich beweisen könnte. Diese Erklärung könnte aber durchaus mit Deiner Lösung zusammenpassen, da Du ja eine temporäre Bitmap erzeugst und deren Canvas manipulierst und dann den ganzen Content in die eigentliche Bitmap rüberkopierst. Und in CopyBitmap wird auch TMonitor verwendet, was auch in Map verwendet wird, so scheint also die Resource bei diesem Verfahren insgesamt schützbar zu sein. |
AW: FMX-TBitmap: Nach Gebrauch von Canvas ins threads unbrauchbar?
Vielen Dank fürs Feedback (gut, dass ich doch nicht spinne :) und die Erklärung dafür, dass meine Reparatur funktioniert, leuchtet mir ein, also BeginScene und Map möglichst getrennt halten.
Hast du auch eine Erklärung dafür, dass die Pointer-Version nicht funktioniert? Ich wollte eigentlich meine ganze Grafik-Bibliothek auf fmx-TBitmap umschreiben, aber wenn der Pointer-Ansatz nicht geht, kann ich die Resampler und Animationen vergessen, schade. Ich habe noch größere Schwierigkeiten als du, den source-code zu verstehen, vor allem, wenn immer noch die styles dareinfunken.. Das Android-Betriebssystem ist mir auch erstmal ein Rätsel, vielleicht sollte ich mal in dein Buch gucken. Danke nochmal, Renate |
AW: FMX-TBitmap: Nach Gebrauch von Canvas ins threads unbrauchbar?
Könntest du mich schlafen? ;-)
Zu FMX gibt's jetzt endlich Andrea Magnani's Buch. Bin aber noch nicht wirklich zum Lesen gekommen... |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:53 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 by Thomas Breitkreuz