我正在使用D3DImage来显示一系列帧,这些帧一帧接一帧渲染到同一Direct3D Surface。因此,我目前的逻辑是:

  • 显示最后渲染的帧(即D3DImage.Lock()/AddDirtyRect()/Unlock())
  • 开始渲染下一帧
  • 等待下一帧准备就绪,现在该显示它了。
  • 显示最后渲染的帧
  • ...

  • 这种方法的问题在于,当我们完成对D3DImage的Unlock()调用后,实际上并没有复制图像,而是仅计划在下一个WPF渲染上复制该图像。因此,有可能在WPF有机会之前在Direct3D曲面上渲染新框架。最终结果是我们在显示器上看到丢失的帧。

    现在,我正在尝试使用单独的Direct3D纹理进行渲染,并在显示之前将其复制到“显示纹理”,这虽然效果更好,但会产生大量开销。最好能够知道D3DImage何时完成刷新并在此之后立即开始渲染下一帧。如果可能的话,这可能吗?还是您有一个更好的主意?

    谢谢。

    最佳答案

    WPF将要渲染时,将调用CompositionTarget.Rendering event,因此您应该执行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;
        }
    }
    

    更新以解决评论

    您确定存在比赛条件吗? This page说,当您调用Unlock()时,后台缓冲区将被复制。

    如果确实存在竞争情况,那么如何在渲染代码周围放置“锁定/解锁”呢? This page表示Lock()将阻塞,直到复制完成。

    10-04 11:16