【问题标题】:How it's possible that calling repaint from a background thread can slow down the animation?从后台线程调用重绘怎么可能减慢动画速度?
【发布时间】:2017-09-03 15:38:01
【问题描述】:

在带有delphi的android下,我有一个后台线程。在这个后台线程中,我调用了一个同步过程,只进行重绘:

TThread.Synchronize(nil,
  procedure
  begin
    repaint;
  end);

要恢复您的 delphi 源代码,在 android repaint 下只需将 bool 设置为 true,告诉主循环器在下一个循环中重新绘制表单:

procedure TPlatformAndroid.InvalidateWindowRect(const AForm: TCommonCustomForm; R: TRectF);
begin
  TAndroidWindowHandle(AForm.Handle).NeedsUpdate := True;
end;

我的表单上还有一个 mousemove 事件,我捕捉到了鼠标移动,我也调用了重绘

procedure TMyFrame.FrameMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
begin
  VPos := Y; 
  repaint;    
end;

我现在完全不明白,是为什么这个重绘(在后台线程中)会在动画中引起一些抖动如果(且仅当)i同时在屏幕上移动我的手指(如果我不移动手指,那么我没有抽搐)

这怎么可能?因为重绘只是简单地将通过鼠标移动(或反之亦然)已经为真的东西变为真。这如何将我的框架的 onpaint 调用延迟超过 100 毫秒(产生抽搐)。从后台线程中删除 onpaint 也删除了混蛋......不知道可能出了什么问题

注意:

如果在TPlatformAndroid.InternalProcessMessages 如果我替换

if TWindowManager.Current.RenderIfNeeds then
    HasEvents := True

通过

TWindowManager.Current.RenderImmediately;
HasEvents := True;

然后滞后消失很多(但不是完全)

【问题讨论】:

  • 所以你从线程内部一遍又一遍地调用Synchronize?通话之间是否有任何延迟?还是他们只是背靠背?如果没有延迟,那么您的线程实际上是在阻止主线程实际上能够完成其工作。与设置布尔值无关,与使用Synchronize 阻塞主线程有关。实际上,这是使线程与主线程通信的一种方式,但是如果您一直背靠背调用它,您就没有给主线程一个完成其工作的机会。至少延迟,但我不知道你为什么需要这个。
  • 作为一个测试,如果你在Synchronize 中注释掉repaint 会发生什么?你仍然观察到滞后吗?
  • 让我们说是,在这个例子中,一遍又一遍。不,它不能阻塞主线程,因为主循环 (TPlatformAndroid.InternalProcessMessages) 执行:processUImessage、Render、processTimerEvent 和 processsynchronize。由于渲染在任何情况下都需要大约 16 毫秒(opengl vsync),那么我们的同步(除了将布尔值设为 true 之外什么都不做)将每 16 毫秒(分钟)执行一次,因此不会影响动画
  • @JerryDodge :不,如果我评论重绘并让同步一切正常,不再滞后......我完全迷失了!
  • 你问了很多非常不清楚的问题,而且没有一个是关于你试图解决的实际问题。似乎所有这些都是关于这个问题OpenGL : how to avoid jerks in scrolling / animations 你没有提供正确的minimal reproducible example。请访问help center 并详细了解该网站的工作原理,否则您将遇到困难。

标签: android delphi firemonkey


【解决方案1】:

好的,我知道原因了。

在 delphi 中,问题在于,即使 repaint 是一个将标志设置为 true 的微不足道的操作,以下实际渲染表单的操作也不是微不足道的,无论如何(即使表单没有改变)这将需要 16 毫秒(垂直同步信号损失)。我的问题也与 ui 事件有关,因为当它们是 ui 事件时,delphi 每 1 毫秒而不是每 10 毫秒触发每个计时器

所以您可以理解,如果我在错误的时间调用重绘(例如,在通常必须触发计时器之前的纳秒),那么我们将有 16 毫秒的延迟等待,然后当计时器触发时,它会为时已晚,我们已经丢了一帧(实际上没有,但最后一次绘画什么也没做),然后我们就会有延迟:(

也是因为这个错误:https://quality.embarcadero.com/browse/RSP-18982

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-26
    • 2017-02-20
    • 1970-01-01
    • 1970-01-01
    • 2013-10-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多