c++ - Direct3D 11 缺少 GetRasterStatus,如何检测垂直空白期?

标签 c++ graphics directx vsync

我正在更新一个应用程序,在该应用程序中,屏幕上刺激呈现时间的测量需要最大的准确性。目前是用DirectDraw写的,很久以前就放牧了,需要更新我们的图形库。

我们测量显示时间的方法是利用检测垂直空白期的结束。具体来说,我需要尽可能准确地知道翻转到主表面(或出现在交换链中)的任何内容何时真正被屏幕绘制。检测扫描线可以增加该测量的确定性,但我只能检测调用 Flip 或 Present 后垂直空白期何时结束。

Direct 3D 9 具有 IDirect3DDevice9::GetRasterStatus Method返回一个 D3DRASTER_STATUS 结构,其中包含一个 InVBlank bool 值,描述设备是否处于垂直空白以及当前扫描线。 DirectDraw 具有类似的功能( IDirectDraw::GetVerticalBlankStatus ,在垂直空白期间返回 DDERR_VERTICALBLANKINPROGRESS 的 IDirectDraw::GetScanLine 也可用于检测 VB)。

但是我没能在 Direct3D11 中找到任何类似的函数。有谁知道此功能是否在 Direct3D9 和 Direct3D11 之间移动或删除,如果是后者,为什么?

最佳答案

很抱歉回复晚了,但我注意到仍然没有公认的答案,所以也许您从未找到有效的答案。如今在 Windows 上,DesktopWindowManager 服务 (dwm.exe) 协调一切,无法真正绕过。自 Windows 8 以来,此服务无法禁用。

因此 DWM 总是会控制帧速率、渲染队列管理以及所有各种 IDXGISurface(n) 对象和 IDXGIOutput(n) 监视器的最终合成,并且在跟踪 VSync 方面没有太大用处屏幕外渲染目标,除非我遗漏了什么(无意讽刺)。至于您的问题,我不确定您的目标是否是:

  1. 获取极其精确的时间信息,但仅用于诊断、分析或信息用途,或者
  2. 应用程序是否会(尝试)使用这些结果来(尝试)安排自己的当前周期。

如果是后者,我相信只有当 D3D 应用程序在全屏独占 模式下运行时,您才能有效地执行此操作。只有这样,DWM(以 DXGI 为幌子)才会真正信任客户端来处理它自己的Present 计时。

这里的(勉强)好消息是,如果您对 VSync 的兴趣仅供引用——也就是说您属于上面的项目符号类别 (1.)——那么您确实可以获得您想要的所有时序数据,以及 QueryPerformanceFrequency 分辨率,通常在 320 ns.¹ 左右

以下是获取高分辨率视频时间信息的方法。但是,再次明确一点,尽管在获取信息方面取得了明显的成功,如下所示,但任何使用这些有趣结果的尝试,例如,将某些确定性的——因此可能有用的——结果作为你获得的读数的条件将注定要失败,也就是说,完全被 DWM 中介所挫败:

DWM_TIMING_INFO

Specifies Desktop Window Manager (DWM) composition timing information. Used by the DwmGetCompositionTimingInfo function.

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 获取数据是现代的方式。

说到现代,因为这个问题暗示了现代化,您需要考虑使用从 IDXGISwapChain1 获得的 IDXGIFactory2::CreateSwapChainForComposition 来启用新的 DirectComposition 组件。

DirectComposition enables rich and fluid transitions by achieving a high framerate, using graphics hardware, and operating independently of the UI thread. DirectComposition can accept bitmap content drawn by different rendering libraries, including Microsoft DirectX bitmaps, and bitmaps rendered to a window (HWND bitmaps). Also, DirectComposition supports a variety of transformations, such as 2D affine transforms and 3D perspective transforms, as well as basic effects such as clipping and opacity.

无论如何,详细的计时信息似乎不太可能有用地告知应用程序的运行时行为; 也许它会帮助您预测您的下一个 VSync,但有人确实想知道“对消隐期的敏锐意识”对某些特定的人可能有什么意义DWM 控制的屏幕外交换链。

因为您的应用程序界面只是 DWM 处理的众多界面之一,所以 DWM 将在假设每个客户端行为一致的情况下自行进行各种动态调整。在这样的制度下,不可预测的适应是不合作的,最终可能只会混淆双方。




注意事项:
1.尽管后者建议使用 100 ns,但 QPC 的分辨率比 DateTime tick 的分辨率高许多数量级。单位面额。将 DateTime.Now.Ticks 视为(毫秒表示的)Environment.TickCount 的重新包装,但转换为 100 ns 单位。要获得尽可能高的分辨率,请使用静态方法 Stopwatch.GetTimestamp() 而不是 DateTime.Now.Ticks

关于c++ - Direct3D 11 缺少 GetRasterStatus,如何检测垂直空白期?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6671420/

相关文章:

C++单链表中的访问冲突读取位置

javascript - 有没有更有效的方法来设置 p5.graphics 像素数组等于另一个使用 JavaScript 中的 p5.js ?

c++ - DirectX 11 : how to define input layout when using more than one vertex buffer?

opengl - 使用 CUDA/OPENCL 直接绘制到屏幕

c++ - 该声明的含义 count[array[i]]

c++ - 自动或手动在C/C++头文件中添加一些注释

math - 平滑地连接两个贝塞尔曲线(C2连续)

assembly - assembly 中的两个堆栈

windows - 获取图形或显存的API

c++ - 将 args 应用于函数的模板函数