很抱歉回复晚了,但我注意到仍然没有接受的答案,所以也许你从来没有找到一个有效的答案。如今在 Windows 上,DesktopWindowManager服务 (dwm.exe) 协调一切,无法真正绕过。从 Windows 8 开始,这个服务就不能被禁用。
所以 DWM 总是要控制所有各种IDXGISurface( n )对象和IDXGIOutput( n )监视器的帧速率、渲染队列管理和最终合成,并且在跟踪离屏渲染目标的VSync方面没有太多用处,除非我遗漏了什么(无意讽刺)。至于你的问题,我不确定你的目标是否是:
- 获取极其精确的时序信息,但仅用于诊断、分析或信息用途,或
- 应用程序是否会(尝试)使用这些结果来(尝试)安排自己的当前周期。
如果是后者,我相信只有在 D3D 应用程序以全屏独占模式运行时才能有效地做到这一点。这是 DWM(以DXGI为幌子)真正信任客户端来处理自己的时间的唯一情况Present
。
这里(几乎没有)好消息是,如果您对VSync的兴趣只是提供信息——也就是说,您从上面属于项目符号类别 (1.),那么您确实可以获得您想要的所有时序数据,以及QueryPerformanceFrequency分辨率,通常约为320 ns。¹
这是获取高分辨率视频计时信息的方法。但是,再次说明一下,尽管在获得如下所示的信息方面取得了明显成功,但任何使用这些有趣结果的尝试,例如,对您获得的读数设置一些确定性的——因此可能有用的——结果将注定要失败,也就是完全被DWM中介阻挠:
DWM_TIMING_INFO
指定桌面窗口管理器 (DWM) 组合计时信息。由DwmGetCompositionTimingInfo函数使用。
typedef struct _DWM_TIMING_INFO
{
UINT32 cbSize; // size of this DWM_TIMING_INFO structure
URATIO rateRefresh; // monitor refresh rate
QPC_TIME qpcRefreshPeriod; // monitor refresh period
URATIO rateCompose; // composition rate
QPC_TIME qpcVBlank; // query performance counter value before the vertical blank
CFRAMES cRefresh; // DWM refresh counter
UINT cDXRefresh; // DirectX refresh counter
QPC_TIME qpcCompose; // query performance counter value for a frame composition
CFRAMES cFrame; // frame number that was composed at qpcCompose
UINT cDXPresent; // DirectX present number used to identify rendering frames
CFRAMES cRefreshFrame; // refresh count of the frame that was composed at qpcCompose
CFRAMES cFrameSubmitted; // DWM frame number that was last submitted
UINT cDXPresentSubmitted; // DirectX present number that was last submitted
CFRAMES cFrameConfirmed; // DWM frame number that was last confirmed as presented
UINT cDXPresentConfirmed; // DirectX present number that was last confirmed as presented
CFRAMES cRefreshConfirmed; // target refresh count of the last frame confirmed as completed by the GPU
UINT cDXRefreshConfirmed; // DirectX refresh count when the frame was confirmed as presented
CFRAMES cFramesLate; // number of frames the DWM presented late
UINT cFramesOutstanding; // number of composition frames that have been issued but have not been confirmed as completed
CFRAMES cFrameDisplayed; // last frame displayed
QPC_TIME qpcFrameDisplayed; // QPC time of the composition pass when the frame was displayed
CFRAMES cRefreshFrameDisplayed; // vertical refresh count when the frame should have become visible
CFRAMES cFrameComplete; // ID of the last frame marked as completed
QPC_TIME qpcFrameComplete; // QPC time when the last frame was marked as completed
CFRAMES cFramePending; // ID of the last frame marked as pending
QPC_TIME qpcFramePending; // QPC time when the last frame was marked as pending
CFRAMES cFramesDisplayed; // number of unique frames displayed
CFRAMES cFramesComplete; // number of new completed frames that have been received
CFRAMES cFramesPending; // number of new frames submitted to DirectX but not yet completed
CFRAMES cFramesAvailable; // number of frames available but not displayed, used, or dropped
CFRAMES cFramesDropped; // number of rendered frames that were never displayed because composition occurred too late
CFRAMES cFramesMissed; // number of times an old frame was composed when a new frame should have been used but was not available
CFRAMES cRefreshNextDisplayed; // frame count at which the next frame is scheduled to be displayed
CFRAMES cRefreshNextPresented; // frame count at which the next DirectX present is scheduled to be displayed
CFRAMES cRefreshesDisplayed; // total number of refreshes that have been displayed for the application since the DwmSetPresentParameters function was last called
CFRAMES cRefreshesPresented; // total number of refreshes that have been presented by the application since DwmSetPresentParameters was last called
CFRAMES cRefreshStarted; // refresh number when content for this window started to be displayed
ULONGLONG cPixelsReceived; // total number of pixels DirectX redirected to the DWM
ULONGLONG cPixelsDrawn; // number of pixels drawn
CFRAMES cBuffersEmpty; // number of empty buffers in the flip chain
}
DWM_TIMING_INFO;
(注:以上源代码横向压缩后在本站展示,假设前面有以下缩写:)
typedef UNSIGNED_RATIO URATIO;
typedef DWM_FRAME_COUNT CFRAMES;
现在,对于在窗口模式下运行的应用程序,您当然可以随心所欲地获取这些详细信息。如果您只需要它进行被动分析,那么从DwmGetCompositionTimingInfo获取数据是实现此目的的现代方式。
说到现代,由于问题暗示了现代化,您需要考虑使用从IDXGIFactory2::CreateSwapChainForComposition获得的 IDXGISwapChain1来启用新的DirectComposition组件。
DirectComposition通过实现高帧率、使用图形硬件以及独立于 UI 线程运行来实现丰富而流畅的过渡。DirectComposition 可以接受由不同渲染库绘制的位图内容,包括 Microsoft DirectX 位图和渲染到窗口的位图(HWND 位图)。此外,DirectComposition 还支持各种变换,例如 2D 仿射变换和 3D 透视变换,以及剪裁和不透明度等基本效果。
无论如何,详细的时间信息似乎不太可能有用地告知应用程序的运行时行为;也许它会帮助您预测您的下一个 VSync,但人们确实想知道“对消隐期的敏锐意识”对于某些特定的 DWM 征服的屏幕外交换链可能具有什么意义。
因为您的应用程序的表面只是 DWM 正在处理的众多问题之一,所以 DWM 将在每个客户端行为一致的假设下进行自己的各种动态适应。在这样的制度下,不可预测的适应是不合作的,而且很可能最终会让双方感到困惑。
注释: 1. QPC 的分辨率比
DateTime
tick 的分辨率高出许多数量级,尽管后者建议使用 100 ns。单位面额。将
DateTime.Now.Ticks
其视为 (millisecond-denoted) 的重新包装
Environment.TickCount
,但转换为 100-ns 单位。要获得尽可能高的分辨率,请使用静态方法
Stopwatch.GetTimestamp()
而不是
DateTime.Now.Ticks
.