【问题标题】:GDI+ flickers even with double-buffering即使使用双缓冲 GDI+ 也会闪烁
【发布时间】:2013-01-12 03:31:33
【问题描述】:

我正在尝试将一个小图像从左侧移动到屏幕右侧。

我将用户控件的样式设置为:

    this.SetStyle(ControlStyles.Opaque, true);
    this.SetStyle(ControlStyles.UserPaint, true);
    this.SetStyle(ControlStyles.ResizeRedraw, true);
    this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);

在我的 OnPaint 处理程序中,我将对象绘制到 BufferedGraphics 实例,这是我的屏幕外缓冲区,然后使用单个调用将结果 BitBlt 到 e.Graphics 引用。

所以我似乎按照书本做了所有事情,以获得超流畅的无闪烁绘图,但我仍然可以看到对象有点口吃。

因此,基本上剩下两种可能性:调用.Invalidate(DirtyRect) 的计时器没有以恒定的时间间隔精确触发,导致对象出现卡顿,或者 BitBlt 没有按预期工作。

有人知道可能是什么问题吗?

更新:再想一想,它看起来更像是撕裂,而不是口吃或闪烁。因为有时对象似乎错过了最后几个像素。我将研究利用 VSYNC 的可能性。

【问题讨论】:

  • 您看到卡顿或闪烁了吗?此外,查看重现代码会很有用...
  • @usr 这很难说。目前它只是一条穿过屏幕的红线,我可以看到它并不完全平滑。我猜它在撕裂,因为这条线是 2 像素宽,而在那些时刻,它似乎只有 1 像素宽。我做了一些研究,没有办法在 WinForms 中利用 VSYNC,所以我想我不走运。
  • 在 TFT 显示器上移动的红线可能由于 TFT 或眼睛的延迟而变得模糊。这与你的观察一致吗?尝试捕获屏幕截图以确认该线实际上是 2px 宽一会儿。
  • @usr 我已经尝试截取问题的屏幕截图,但它从未出现,但可能是 Windows 在合适的时刻(垂直同步之间)捕获屏幕截图。此外,问题不在于线条看起来更宽(会变得模糊),而是看起来更细。
  • 你用什么定时器? (默认的 Timer 类对于平滑动画来说不够准确 - GDI+ 也不适合这个问题)。 GDI+ 不允许您通过 vsync(或 vblank)进行同步,因此您需要为此设置低级别。 Invalidates 最终会在可能时呈现的队列中结束。您可以使用 Refresh (invalidate + Update) 强制更新

标签: .net gdi+ gdi flicker double-buffering


【解决方案1】:

这可能完全没有帮助,但我遇到了类似的问题,我花了很长时间才弄清楚,所以我会提到它。由于我的 CPU 在多个内核上管理性能计数器的方式,我遇到了一个特定于硬件的问题,它破坏了计时器的准确性。

长话短说,在升级计算机之前,我必须在单核上运行主要的 OpenGL 循环。如果在屏幕上移动字形之前运行以下代码(或类似代码)有帮助,那么您将遇到同样的问题。这是c#版本。

Process.GetCurrentProcess().ProcessorAffinity = (IntPtr)1;

我希望这会有所帮助。但是,我也希望这不是你的问题。保重。

【讨论】:

    猜你喜欢
    • 2011-01-22
    • 1970-01-01
    • 2015-05-01
    • 1970-01-01
    • 2018-11-15
    • 1970-01-01
    • 2012-08-27
    • 2019-06-12
    • 1970-01-01
    相关资源
    最近更新 更多