抱歉回复晚了,但我注意到还没有被接受的答案,所以也许你从未找到有效的解决方案。现在在Windows上,
DesktopWindowManager服务(dwm.exe)协调一切,无法真正绕过。自从Windows 8以来,该服务就无法禁用。
因此,DWM始终会控制所有各种
IDXGISurface(n)对象和
IDXGIOutput(n)监视器的帧速率、渲染队列管理和最终合成,并且在追踪离屏渲染目标的VSync方面没有太大用处,除非我漏了什么(无意挖苦)。至于您的问题,我不确定您的目标是:
- 获取极其精确的时间信息,但仅用于诊断、分析或信息用途,或者
- 应用程序是否会(尝试)使用这些结果来(尝试)安排自己的当前周期。
如果是后者,我认为您只能在D3D应用程序运行在全屏独占模式下有效地执行此操作。这是唯一一种情况,DWM - 以DXGI的形式 - 将真正信任客户端处理自己的Present
计时的情况。
这里的好消息(勉强算是)是,如果你对于VSync只是纯粹的信息需求——也就是说你属于上面所提到的第一类——那么你确实可以获得所有你想要的时间数据,并且在QueryPerformanceFrequency分辨率下,通常约为320 ns.¹。
以下是如何获取高分辨率视频定时信息。但需要再次明确的是,尽管下面的结果显示已经成功获取了信息,但任何试图使用这些有趣的结果的尝试,例如将某些确定性的——因此可能有用的——结果条件化为你所获得的读数,都将注定失败,即完全被DWM中介所挫败:
DWM_TIMING_INFO
指定桌面窗口管理器(DWM)合成时序信息。由DwmGetCompositionTimingInfo函数使用。
typedef struct _DWM_TIMING_INFO
{
UINT32 cbSize;
URATIO rateRefresh;
QPC_TIME qpcRefreshPeriod;
URATIO rateCompose;
QPC_TIME qpcVBlank;
CFRAMES cRefresh;
UINT cDXRefresh;
QPC_TIME qpcCompose;
CFRAMES cFrame;
UINT cDXPresent;
CFRAMES cRefreshFrame;
CFRAMES cFrameSubmitted;
UINT cDXPresentSubmitted;
CFRAMES cFrameConfirmed;
UINT cDXPresentConfirmed;
CFRAMES cRefreshConfirmed;
UINT cDXRefreshConfirmed;
CFRAMES cFramesLate;
UINT cFramesOutstanding;
CFRAMES cFrameDisplayed;
QPC_TIME qpcFrameDisplayed;
CFRAMES cRefreshFrameDisplayed;
CFRAMES cFrameComplete;
QPC_TIME qpcFrameComplete;
CFRAMES cFramePending;
QPC_TIME qpcFramePending;
CFRAMES cFramesDisplayed;
CFRAMES cFramesComplete;
CFRAMES cFramesPending;
CFRAMES cFramesAvailable;
CFRAMES cFramesDropped;
CFRAMES cFramesMissed;
CFRAMES cRefreshNextDisplayed;
CFRAMES cRefreshNextPresented;
CFRAMES cRefreshesDisplayed;
CFRAMES cRefreshesPresented;
CFRAMES cRefreshStarted;
ULONGLONG cPixelsReceived;
ULONGLONG cPixelsDrawn;
CFRAMES cBuffersEmpty;
}
DWM_TIMING_INFO;
(注:为了在此网站上水平压缩上面的源代码,请假设以下缩写已添加到前面。)
typedef UNSIGNED_RATIO URATIO;
typedef DWM_FRAME_COUNT CFRAMES;
现在对于以窗口模式运行的应用程序,您可以随时获取此详细信息。 如果您只需要它进行被动分析,则从
DwmGetCompositionTimingInfo获取数据是现代化的方法。
而且,说到现代化,既然问题暗示了现代化,您会想要考虑使用从
IDXGIFactory2::CreateSwapChainForComposition获得的
IDXGISwapChain1来启用新的
DirectComposition组件的使用。
DirectComposition 通过使用图形硬件以及独立于 UI 线程的方式实现高帧率,从而实现丰富流畅的转换。DirectComposition 可以接受由不同渲染库绘制的位图内容,包括 Microsoft DirectX 位图和绘制到窗口 (HWND 位图) 的位图。此外,DirectComposition 支持各种变换,例如二维仿射变换和三维透视变换,以及基本效果,如裁剪和不透明度。
无论如何,详细的时间信息似乎很少对应用程序的运行时行为有用;可能它会帮助您预测下一个 VSync,但是一个人确实会想知道 "对消隐期的敏锐感知" 对某个特定的 DWM-受制于屏幕外交换链有什么意义。
因为您的应用程序表面只是 DWM 正在处理的许多表面之一,DWM将会进行各种动态自适应,假定每个客户端都具有一致的行为。在这样的统治下,不可预测的自适应会不合作,并且很可能会使双方都困惑。
注意:1. 尽管
DateTime
使用100纳秒单位,但QPC的分辨率比它高几个数量级。将
DateTime.Now.Ticks
视为重新打包(以毫秒表示)的
Environment.TickCount
,但转换为100纳秒单位。为获得最高分辨率,请使用静态方法
Stopwatch.GetTimestamp()
而不是
DateTime.Now.Ticks
。