阻止画布

时间:2018-06-08 12:00:29

标签: delphi canvas bitmap firemonkey

我有一个我的应用程序的形式,可以有多达1000个可视组件,其中我使用位图的Canvas绘制每一个,并保存每个组件的位图(一种双缓冲),因为每个操作需要20毫秒。

我正在使用线程绘制位图并使用此位图向MainThread发送通知,以刷新可视组件,UI。

理论上,它必须有一个流体形式的开口,当它们的位图涂在螺纹中时显示组件,但实际上它不是流动的。我决定看看delphi的TCanvas,我发现了一些令人震惊的事情:

class var // <<<<<<<<<<<<<<<<<<<<<<<<<<<< class var
  FLock: TObject;

function TCanvas.BeginScene(AClipRects: PClipRects = nil; AContextHandle: THandle = 0): Boolean;
begin
  Lock;
  ...
end;

procedure TCanvas.EndScene;
begin
  ...
  Unlock;
end;

class procedure TCanvas.Lock;
begin
  TMonitor.Enter(FLock);
end;

class procedure TCanvas.Unlock;
begin
  TMonitor.Exit(FLock);
end;

这绝对不对。为什么embarcadero无法在不同的线程中同时使用TCanvas?创建10个线程来进行位图绘制是没有用的,因为一次只能处理1个...

  1. 为什么会这样?
  2. 有没有解决方法?如果我制作我的版本会发生什么 FMX.Graphics每个TCanvas只有本地监视器?
  3. 是否有任何第三方lib拥有它自己的TCanvas?
  4. 我知道很多人会建议我使用本机类,Android中的JCanvas和iOS中的CGContextRef,但我想要一个TCanvas的解决方案,因为它的工作是成为绘制所有平台功能的包装器,并且很容易使用。

    ============= @EDIT =============

    我在FMX.Graphics单元中更改了TCanvas的锁定和解锁,以使用本地而不是全局监视器,以及FMX.Types3D单元中TContext3D的BeginScene和EndScene。 我对这一变化非常担心,但显然应用程序正常工作,最大的工作是重新编译整个FMX。

1 个答案:

答案 0 :(得分:1)

Tbitmap并不是真正的多线程。它在Delphi东京被制作为多线程但设计非常糟糕(当你在后台线程中使用Tbitmap时,它们仍然是很多bug,例如Tbitmap仍然使用根本不是多线程的消息通知,因此可能导致随机例外)。在tokyo中做得不错的是使OpenGL上下文多线程(在android / ios下),并且工作得很好(但不是仍然绑定到Messaging的TTexture,但你可以轻松更新ttexture的源代码来纠正它(您可以查看Alcinoe的源代码以了解如何操作)。

您希望实现的唯一解决方法是:

  1. 不要使用TBitmap而是使用Texture(因为openGL完全多线程没有任何锁定)
  2. 使用本机操作系统功能在后台线程中构建纹理(Android中的JCanvas和iOS中的CGContextRef)
  3. 避免使用如此多的控件,而是在正确的位置自行绘制主线程中准备好和可见的所有纹理(所以在onpaint事件中)
  4. 是的,我知道这很痛苦!