在使用DWM组合的窗口上使用GDI绘图时,是否可以防止撕裂伪影?

Dav*_*vid 14 windows winapi gdi dwm

我在窗口上,在启用了DWM组合的系统上使用双缓冲GDI绘制动画,并在屏幕上看到清晰可见的撕裂.有办法防止这种情况吗?

细节

动画采用相同的图像,并在屏幕上从右向左移动; 像素跨越由当前时间和动画开始时的时间和时间,以端之间的差确定的数量,以便获得完整的一小部分被施加到整个窗口宽度,使用timeGetTime具有1毫秒的分辨率.动画绘制循环而不处理应用程序消息; 它调用Repaint内部无效的(VCL库)方法,然后调用UpdateWindow有问题的窗口,直接调用消息过程WM_PAINT.绘图处理程序的VCL实现使用BeginBufferedPaint.绘画本身是双重缓冲的.

这样做的目的是使帧速率尽可能高,以在屏幕上获得平滑的动画效果.(该图使用双缓冲来消除闪烁并确保整个图像或帧在任何时间都在屏幕上.它通过调用消息过程直接无效和更新,而不进行其他消息处理.绘画使用现代技术实现(例如,BeginAfferedPaint)用于Aero组合.)在此之内,绘画是在几个BitBlt调用中完成的(一个用于动画的左侧,即在屏幕外移动,一个用于动画的右侧,即在屏幕上移动的内容). )

观看动画时,会有明显的撕裂现象.这种情况发生在具有不同图形卡的多个系统上的Windows Vista,7和8.1上.

我处理这个问题的方法是降低绘图速度,或者在再次绘制之前尝试等待VSync.这可能是错误的方法,所以这个问题的答案可能是"完全做其他事情:X".如果是这样,很棒:)

(我真正喜欢的是一种让DWM为这个特定窗口组成/仅使用完全绘制的帧的方法.)

我尝试了以下方法,其中没有一个删除所有可见的撕裂.因此问题是,在使用DWM组合时是否可以避免撕裂,如果是这样的话?

方法尝试:

  • 获取显示器刷新率GetDeviceCaps(Application.MainForm.Handle, VREFRESH); 睡眠1 /刷新率毫秒.尽可能快地改善绘画,但可能是一厢情愿的想法.感觉上动画率稍微不那么平滑.(调整:正常Sleep和高分辨率旋转等待使用timeGetTime.)

  • 使用DwmSetPresentParameters尝试更新限制到该代码绘制相同的速度.(变化:大量缓冲区(cBuffer = 8)(无可见效果);使用上面的代码指定监视器刷新率/ 1和睡眠的源速率(与尝试休眠方法相同);指定每帧的刷新次数1,10等(无可见效果);更改源帧覆盖范围(无可见效果)

  • 使用DwmGetCompositionTimingInfo在多种方式:

      • cFramesPending> 0时,旋转;
      • 得到cFrame(框架组合)并旋转,而这个数字不会改变;
      • 获得cFrameDisplayed并旋转,而这不会改变;
      • 通过添加计算睡眠时间qpcVBlank + qpcRefreshPeriod,然后在QueryPerformanceCounter返回时间小于此时旋转
  • 所有这些方法也通过绘画,然后在再次绘画之前旋转/睡觉而变化; 或者相反:睡觉然后画画.

似乎没有任何可见效果,并且有什么效果很难获得资格,可能只是帧率较低的结果.没有防止撕裂,即没有人使DWM用窗口DC内容的"整体"副本组成窗口.

建议赞赏:)

Chr*_*s O 3

由于您使用的是BitBlt,请确保您的 DIB 为 4 字节/像素。对于 3 字节/像素,当 DWM 运行时,GDI 速度非常慢,这可能是造成撕裂的根源。我遇到的另一个BitBlt问题是,如果您的 DIB 稍大,则调用BitBlt会花费意想不到的长时间。如果您将一个调用拆分为更小的调用,而不是仅绘制一部分数据,这可能会有所帮助。这两个项目对我的情况都有帮助,只是因为BitBlt它们本身运行太慢,从而导致视频伪影。