繁体   English   中英

如何检测何时重绘WPF控件?

[英]How to detect when a WPF control has been redrawn?

我正在使用D3DImage显示一系列帧,这些帧一个接一个地呈现在同一个Direct3D Surface中。 我现在的逻辑是这样的:

  • 显示最后渲染的帧(ieD3DImage.Lock()/ AddDirtyRect()/ Unlock())
  • 开始渲染下一帧
  • 等待下一帧准备就绪,是时候显示它了
  • 显示上次渲染的帧
  • ...

这种方法的问题在于,当我们在D3DImage上调用Unlock()时,图像实际上没有被复制,它只被安排在下一个WPF渲染上复制。 因此,在WPF有机会显示之前,我们可能会在Direct3D表面上渲染一个新帧。 最终结果是我们在显示器上看到错过的帧。

现在我正在尝试使用单独的Direct3D纹理进行渲染,并在显示之前执行复制到“显示纹理”,这样可以提供更好的结果,但会产生大量的开销。 最好能够知道D3DImage何时完成刷新并立即开始渲染下一帧。 这有可能,如果是这样的话怎么样? 或者你有一个更好的想法?

谢谢。

当WPF要渲染时,会调用CompositionTarget.Rendering事件 ,因此应该执行Lock()Unlock() Unlock() ,您可以启动下一个渲染。

您还应该检查RenderingTime因为事件可能每帧触发多次。 尝试这样的事情:

private void HandleWpfCompositionTargetRendering(object sender, EventArgs e)
{
    RenderingEventArgs rea = e as RenderingEventArgs;

    // It's possible for Rendering to call back twice in the same frame
    // so only render when we haven't already rendered in this frame.
    if (this.lastRenderTime == rea.RenderingTime)
        return;

    if (this.renderIsFinished)
    {
        // Lock();
        // SetBackBuffer(...);
        // AddDirtyRect(...);
        // Unlock();

        this.renderIsFinished = false;
        // Fire event to start new render
        // the event needs to set this.renderIsFinished = true when the render is done

        // Remember last render time
        this.lastRenderTime = rea.RenderingTime;
    }
}

更新以解决评论

你确定有竞争条件吗? 此页面表示在调用Unlock()时会复制后台缓冲区。

如果确实存在竞争条件,那么在渲染代码周围放置锁定/解锁怎么样? 此页面表示Lock()将阻止,直到副本完成。

为了与UI并行渲染,看起来干净的方式是渲染到单独的D3D表面,并将其复制到锁定调用之间的显示表面(即传递给SetBackBuffer的表面)( )和解锁()。 所以算法变成:

  1. 复制并显示最后渲染的帧,即
    • Lock()
    • 从渲染复制到显示表面
    • SetBackBuffer(displaySurface)
    • AddDirtyRect()
    • Unlock()
  2. 将新渲染计划到渲染表面
  3. 等待它完成,并且时间可以显示它
  4. 转到1

D3DImage的文档明确指出

在D3DImage解锁时不要更新Direct3D表面。

这里的痛点是副本,这可能是昂贵的(即如果硬件繁忙则> 2ms)。 为了在D3DImage解锁时使用显示器表面(避免在渲染时可能进行昂贵的操作),人们不得不求助于反汇编和反射来挂钩到D3DImage自己的渲染中......

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM