等待VBLANK以窗口模式出现在Windows 10上的正确方法是什么?目前,我正在执行以下操作:

D3DKMTWaitForVerticalBlankEvent(&waitData);
swapchain->Present(0, 0);

但是,这会导致偶尔的断断续续。我目前关于口吃的理论如下:
DWM在VBLANK事件之前的某个时候完成合成,然后在VBLANK间隔期间,DWM尝试尽可能快地写入前端缓冲区。因此,如果在VBLANK间隔中调用Present,则可能在DWM已写入前端缓冲区之后发生。这是我脑海中的照片:
winapi - 在窗口模式下在Windows 10上等待VBLANK的正确方法-LMLPHP

因此,更正确的方法是在VBLANK之前调用Present(1, 0),以将窗口的后台缓冲区与DWM排队。然后调用D3DKMTWaitForVerticalBlankEvent等待下一个VBLANK。那是:
swapchain->Present(1, 0);
D3DKMTWaitForVerticalBlankEvent(&waitData);

带有相应的图片:
winapi - 在窗口模式下在Windows 10上等待VBLANK的正确方法-LMLPHP
第二种方法似乎完美地工作,不再有结结巴巴的情况。

我的问题是:
在VBLANK间隔中呈现的正确方法是什么?
我的理论是正确的还是发生了更复杂/更简单的事情?
还有没有资源可以了解有关此交互作用的更多信息?

可能有用的链接:
MSDN Present
DXGI Best Practices
DXGI Waitable Swap Chain
D3DKMTWaitForVerticalBlankEvent

编辑:
不知道这应该是答案还是编辑。
经过一番谷歌搜索后,我发现this explanation by Nicholas Steel似乎与我的理论相符



因此,最好的办法是:
if (DWM.isEnabled())
{
    present();
    DwmFlush();
}
else
{
    waitForVBlank();
    present();
}

另一个编辑:
对于将来的读者,还有其他两种等待VBLANK的方式,我不知道它们是IDXGIOutput::WaitForVBlankIDirectDraw7::WaitForVerticalBlank(后者已弃用)。

最佳答案

您为什么要在窗口模式下等待VBLANK? DWM将确保复合表面在VBLANK区域内翻转。

当您说“DWM在VBLANK事件之前的某个时间完成合成”时,什么使DWM启动合成?在出现任何应用程序或焦点应用程序之后,都不会发生这种情况。 VBLANK发生时实际上开始合成。它可能会完成并翻转VBLANK中的合成表面,或者可能最终实际上翻转了下一个VBLANK(因此您可能会在等待时间中得到额外的帧持续时间)。不过,这不在您的控制范围内-它取决于编写的持续时间,而不取决于应用程序的当前状态。

在带窗口的应用程序中,当您调用present时,它只会翻转应用程序的交换链-不会翻转显示的表面。 DWM将处理该问题。因此,“只要合成器处于 Activity 状态,您就不必再担心自己轮询VBlank了。”

但是,使用DwmFlush()来实现“在每个VBlank周期之间最多将1个新的视频帧呈现给合成器”并不是必须的。除非您确实只想在每个监视器周期显示1帧,否则您可以这样做(尽管我不确定DwmFlush()是否是最优雅的方法)。但是在大多数情况下,我认为强制执行该限制是不可取的。

关于winapi - 在窗口模式下在Windows 10上等待VBLANK的正确方法,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49244480/

10-11 02:14