硬件翻转队列

本文介绍从 Windows 11 (WDDM 3.0) 开始支持的硬件翻转队列功能。 硬件翻转队列功能允许将多个将来的帧提交到显示控制器队列。 当显示控制器处理多个排队帧时,CPU 和 GPU 的部件可以转换为低功率状态,从而提高支持的硬件上的视频播放方案的电源效率。

WDDM 3.0 之前的翻转队列模型

许多新式显示控制器支持将序列中显示的多个帧排队的功能。 从 WDDM 2.1 开始,OS 支持下一个 VSync 上显示的多个未完成的翻转覆盖请求。 显示微型端口驱动程序 (KMD) 通过 DXGK_DRIVERCAPS 中的 MaxQueuedMultiPlaneOverlayFlipVSync 值指示此支持。 此功能对于降低高帧速率游戏场景中的延迟很有用,在这些场景中,多个帧以间隔 0 的顺序呈现,目的是仅显示最新的帧。

在视频播放方案中,要按顺序显示的多个未来帧的内容是事先知道的,并且可以排队到 GPU。 这种提前排队允许 CPU 在处理排队的帧时进入低功耗状态,从而大幅节省电量。 但是,在 WDDM 3.0 之前,OS 没有机制可以提交需要在屏幕上至少保留一个 VSync 间隔的多个帧,而无需进一步的 CPU 干预。 基本硬件翻转队列部分介绍了一种解决方案,该解决方案使 CPU 能够进入低功耗状态,并将排队帧处理卸载到 GPU。

在 WDDM 3.0 之前的游戏中,GPU 完成将场景呈现到交换链后台缓冲区后,会往返 CPU,以便提交请求以将帧内容呈现到屏幕。 对于接近 VSync 的繁重 GPU 工作负载,这种往返可能会导致帧延迟并错过预期目标时间,从而导致可观察到的帧故障。 “高级硬件翻转队列”部分引入了一种机制,可避免这种 CPU 往返,并且以非常低的延迟将已完成的帧呈现到屏幕。 高级硬件翻转队列需要提供基本硬件翻转队列和 GPU 硬件计划阶段 2 功能。

基本硬件翻转队列

下图演示了显示三个帧的情况,每个帧在屏幕上停留一个 VSync 间隔。

显示三个帧在屏幕上停留一个 VSync 间隔的示意图。

图中的填充模式显示了 Dxgkrnl 软件翻转队列处理和应用程序线程必须唤醒并执行 CPU 工作的时间。 在每个 VSync 上,显示控制器必须向 OS 发出 CPU 通知,以便完成翻转,并且 OS 必须提交下一个翻转请求。 应用程序还必须在每个 VSync 上唤醒并查询呈现的统计信息,以便最终了解何时显示第三个批中的最后一帧。

从 WDDM 3.0 开始,可以使用可将多个未来帧提交到显示控制器队列的硬件翻转队列 DDI。 如前所述,此机制允许 CPU 和 GPU 的部件在显示控制器处理多个排队帧时转换为低功耗状态,从而提高支持的硬件上的视频播放方案的电源效率。

下图演示了建议的体系结构。

演示基本硬件翻转队列机制的示意图。

使用硬件翻转队列方法时,应用程序和 Dxgkrnl CPU 组件在 v2v4 之间的两个 VSync 间隔内处于完全空闲状态,从而使 CPU 进入低功耗状态。 仅当应用程序请求等待的帧 N+2 完成时,才会通知 CPU。

高级硬件翻转队列

在 WDDM 3.0 之前的游戏中,在 GPU 完成将场景呈现到交换链后台缓冲区后,会往返于 CPU,以便提交请求以将帧内容呈现到屏幕。 下图显示了此方案。

描述需要 CPU 往返的帧完成的示意图。

如果渲染完成得离 VSync 太近,则此往返成本可能会导致帧错过目标,如下图所示。

说明由于所需的 CPU 往返而错过的帧的关系图。

某些显示控制器本身支持等待条件,允许显示器在 GPU 完成呈现帧后提交翻转请求,而无需 CPU 往返。 由于硬件翻转队列可以在没有 CPU 往返的情况下将刚刚完成的帧 N 提交到显示器,因此可以避免错过帧,如下图所示。

显示帧完成而无需 CPU 往返的示意图。

本文的其余部分讨论基本的硬件翻转队列功能。

DDI 支持

添加了以下 DDI 以支持硬件翻转队列功能。

检查功能可用性

硬件翻转队列需要 OS 启用/禁用协商。 支持硬件翻转队列的 KMD 必须先在设备启动期间调用 DXGKCB_QUERYFEATURESUPPORT其 FeatureId为 DXGK_FEATURE_HWFLIPQUEUE ,以确定 OS 是否允许启用硬件翻转队列。

仅当回调成功且 Enable 设置为 TRUE 时,才能使用硬件翻转队列。

KMD 可以在硬件翻转队列启动和试验阶段使用以下示例代码。


DXGKARGCB_QUERYFEATURESUPPORT HwFlipQueueEnabledArgs = {};
HwFlipQueueEnabledArgs.DeviceHandle = DeviceHandle;
HwFlipQueueEnabledArgs.FeatureId = DXGK_FEATURE_HWFLIPQUEUE;
HwFlipQueueEnabledArgs.DriverSupportState = DXGK_FEATURE_SUPPORT_EXPERIMENTAL;

if (!NT_SUCCESS(pDxgkInterface->DxgkCbQueryFeatureSupport(&HwFlipQueueEnabledArgs)) ||
    !HwFlipQueueEnabledArgs.Enabled)
{
    // Disable hardware flip queue because the OS didn't allow it.           
}
else
{
    // Enable hardware flip queue because the OS allowed it.
}

在驱动程序启动期间,即使可以在不启用 GPU 硬件计划的情况下启用硬件翻转队列,但此组合不受官方支持。 Windows 当前要求启用 GPU 硬件计划,以便在正式发布的驱动程序上启用基本硬件翻转队列。

指示硬件队列功能

MaxHwQueuedFlips 已添加到 DXGK_DRIVERCAPS ,以指示硬件翻转队列支持。 如果 OS 允许的硬件翻转队列支持如前所述,则支持硬件翻转队列的 KMD 应将 MaxHwQueuedFlips 设置为大于 1 的值。 当 MaxHwQueuedFlips 大于 1 时,KMD 指示显示硬件最多支持 MaxHwQueuedFlips 未来帧,这些帧可以排队以便为 GPU 上的给定 VidPnSource 显示。 OS 将遵循驱动程序提供的关于可提前排队的翻转类型的限制。

HwQueuedFlipCaps 也添加到 DXGK_DRIVERCAPS。 此成员目前保留供系统使用,不应由驱动程序使用。

翻转目标时间和目标时间戳格式

当 OS 向硬件翻转队列提交翻转请求时,它还会发送目标翻转时间。 达到目标翻转时间后,用户可以看到翻转。

OS 使用从 KeQueryPerformanceCounter 获取的 CPU 时钟计数器单位传递目标帧时间并解释实际帧时间。

提交排队翻转

传递给 KMD 的 DxgkDdiSetVidPnSourceAddressWithMultiPlaneOverlay3 回调函数的 DXGKARG_SETVIDPNSOURCEADDRESSWITHMULTIPLANEOVERLAY3 结构进行了如下修改,以启用排队翻转的提交:

  • 以下三个成员已添加到 OutputFlagsDXGK_SETVIDPNSOURCEADDRESS_OUTPUT_FLAGS 结构中。 有关这些成员的详细信息,请参阅 DxgkDdiSetVidPnSourceAddressWithMultiPlaneOverlay3 重试和失败案例

    • HwFlipQueueDrainNeeded
    • HwFlipQueueDrainAllPlanes
    • HwFlipQueueDrainAllSources
  • 添加了 TargetFlipTime 成员。 TargetFlipTime 以 QPC 单位描述目标翻转时间。 当时钟达到此值时,帧可以发送到显示器,同时遵循 VSync 和撕裂标志。 如果存在以前排队的挂起翻转,OS 保证对于翻转请求引用的每个 MPO 平面, TargetFlipTime 大于或等于此平面的任何挂起翻转目标时间。 换句话说,可以有一个具有相同或增加时间戳的翻转序列,但不能有一个序列会追溯到时间。

DxgkDdiSetVidPnSourceAddressWithMultiPlaneOverlay3 重试和失败案例

由于挂起的翻转,无法将请求排队到硬件

有几个特殊情况可能会阻止 KMD 在其他翻转请求挂起时将翻转请求排队。 在这种情况下,KMD 应从 DxgkDdiSetVidPnSourceAddressWithMultiPlaneOverlay3 返回STATUS_RETRY,并将 HwFlipQueueDrainNeeded 设置为等于 1。 在完成受此翻转影响的飞机上所有挂起的翻转后,操作系统将再次尝试提交翻转请求,并且一旦达到目标时间。

在某些情况下,显示硬件可能需要完成所有平面上的挂起翻转,而不仅仅是传入翻转请求引用的翻转。 在这种情况下, HwFlipQueueDrainNeededHwFlipQueueDrainAllPlanes 标志都应设置为 1,KMD 应返回STATUS_RETRY。

同样,显示硬件可能需要完成所有 VidPn 源上的挂起翻转才能重新分配内部资源,在这种情况下,必须设置 HwFlipQueueDrainAllSourcesHwFlipQueueDrainNeeded 标志,KMD 应返回STATUS_RETRY。

此外,KMD 可以向 OS 指示是否应在将 PrePrePresentNeeded 设置为 0) 的设备 IRQL (执行重新提交,或者操作系统是否应在将 PrePresentNeeded 设置为 1) PASSIVE_LEVEL (执行此调用。 如果 KMD 仍然返回STATUS_RETRY即使该 VidPnSourceId 上没有更多挂起的翻转,此条件将被视为 无效参数失败

MaxHwQueuedFlips 的值仍然反映可排队到 MPO 平面的仅限地址的简单更改翻转的最大数目,这一点很重要。 STATUS_RETRY机制应用于无法深入排队的更复杂的翻转请求,例如平面配置更改。

无效参数失败

在硬件翻转队列模型中,OS 对失败翻转请求的处理进行了重新处理,以实现更好的可调试性。 当 KMD 无法处理翻转请求时,它应从 DxgkDdiSetVidPnSourceAddressWithMultiPlaneOverlay3 返回STATUS_INVALID_PARAMETER。 根据 OS 设置,OS 将执行以下操作之一:

  • 内核调试器中断和 bug 检查:在发生故障时,通常会在开发/预发布版本上启用此行为,以提高可调试性。
  • 实时内核转储后跟 TDR:零售最终用户行为。

指定 VSync 中断行为

为了在排队翻转方案中实现节能,OS 通常会暂停常规 VSync 中断,使 CPU 保持低功耗状态。 但是,某些翻转将被标记为需要引发中断,以便应用程序观察一批已完成的演示并排队进一步的工作。 在某些情况下,无论是否有挂起的翻转请求,应用程序都会在每个 VSync 中断上请求唤醒。 相反,在完全空闲的系统上,VSync 中断会暂停,直到出现新的演示活动或 VSync 侦听器。

为了处理所有这些情况,引入了以下驱动程序回调和回调结构:

KMD 提供指向其 DxgkDdiSetInterruptTargetPresentId 函数 的指针DRIVER_INITIALIZATION_DATA

OS 调用 DxgkDdiSetInterruptTargetPresentId 以指定目标 PresentId,该目标 PresentId 应在相应的翻转完成时引发 VSync 中断。 它在设备中断级别调用, (DIRQL) 与 DxgkDdiSetVidPnSourceAddress 和 VSync 中断同步。

与 DxgkDdiControlInterrupt 交互

当通过 DxgkDdiControlInterrupt DxgkDdiControlInterrupt2/DxgkDdiControlInterrupt3 完全禁用 VSync 中断时,无论中断目标 PresentId 值如何,它们都会保持禁用状态。/ 需要 KMD 来存储最新的中断目标当前 ID,以便在再次启用 VSync 后可以遵循它。

通过 DxgkDdiControlInterruptXxx 启用 VSync 中断时,中断目标当前 ID (pSetInterruptTargetPresentId) 提供细化控制,如下所示:

  • 当目标当前 ID 设置为 UINT64_MAX 时,在目标当前 ID 再次更改之前,无需进行 VSync 中断。 已禁用 VSync 中断,但需要 KMD 来实现重新启用中断 DXGK_VSYNC_DISABLE_KEEP_PHASE 行为。

  • 当目标当前 ID 设置为 0 时,每个 VSync 都需要中断。

  • 对于任何其他现有 ID 值,如果当前扫描的 PresentId >= InterruptTargetPresentId,则会引发中断。

当有多个 MPO 平面可用时,如果任何平面需要 VSync 中断,则应引发该中断。

使用 DxgkDdiSetInterruptTargetPresentId 禁用 2 阶段 VSync

如果 OS 对 DxgkDdiSetInterruptTargetPresentId 的调用在平面上设置了 InterruptTargetPresentId ,这将导致在此 VidPnSource (上完全禁用 VSync,也就是说,此平面是最后一个保持启用 VSync 的平面,现在它正在禁用 VSync 以及) ,KMD 应禁用 VSync 中断,但使硬件中的 VSync 阶段保持启用 (DXGK_VSYNC_DISABLE_KEEP_PHASE) 。 在一定时间段 (通常相当于两个 VSync 周期) 之后,OS 将随后调用带有DXGK_VSYNC_DISABLE_NO_PHASE的 DxgkDdiControlInterruptXxx 。 此调用可确保 KMD 有机会禁用 VSync 阶段和 VSync 时钟,以节省最大功率,并与非硬件翻转队列系统保持性能奇偶一性。

排队翻转取消

在全屏状态转换或应用程序退出等情况下,可能需要取消将来排队的翻转。 为了处理这些情况,引入了以下驱动程序回调和相关结构:

KMD 在 DRIVER_INITIALIZATION_DATA 中提供指向其 DxgkDdiCancelFlips 函数 指针。

OS 指定在调用 DxgkDdiCancelFlips 时要取消的排队翻转范围,KMD 将能够同步取消的翻转范围报告给 OS。

以下示例演示了单平面上翻转取消的机制和同步情况。 (OS 在 Windows 11 版本 22H2.) 中不支持异步取消,假设以下翻转正在排队到硬件翻转队列:

  • PresentId N
  • time t0 PresentId N+1
  • time t1 PresentId N+2
  • time t2 PresentId N+3
  • time t3 PresentId N+4
  • time t4

然后,OS 决定取消翻转 N+2N+3N+4,因此它会调用 DxgkDdiCancelFlips ,并将 PresentIdCancelRequested 设置为 N+2

当 KMD 检查硬件翻转队列状态时,它确定翻转 N+2 已发送到显示硬件,在调用时无法取消,但 N +3N+4 可以同步从硬件翻转队列中删除,而不会产生副作用。 KMD 将 PresentIdCancelled 设置为 N+3 ,并照常完成 N+2

OS 会将 N+3N+4 标记为已取消,并将 NN+1N+2 视为未完成。 当引发下一个 VSync 中断时,翻转队列日志将像往常一样指示 NN+1N+2 的时间戳。

同步取消翻转的范围必须是连续的,如果不是零,则假定包括提交到 KMD 的最后一个当前 ID。 换句话说,这两个同步取消翻转范围内不能有空隙。

取消多个平面上的互锁翻转

通过使用多个平面和 PresentIds 调用 DxgkDdiSetVidPnSourceAddress 来提交互锁翻转。 OS 与 KMD 之间的协定如下:

  • 平面集必须在同一 VSync 上可见。
  • 不允许显示硬件仅在一个 VSync 上显示这些平面的子集,而其余的显示在下一个 VSync 上。

在硬件翻转队列模型中,通过在对 DxgkDdiCancelFlips 的调用中传递多个平面和 PresentId 来取消此类互锁翻转。 在这种情况下传递的平面集必须对应于挂起的互锁翻转请求,并且 KMD 关于所有互锁 PresentId 的决定必须相同:

  • 不取消,或
  • 同步取消

在设备中断级别调用 DxgkDdiCancelFlips, (DIRQL) 与 DxgkDdiSetVidPnSourceAddress 和 VSync 中断同步。

获取排队翻转的当前统计信息

由于硬件翻转队列方法是避免唤醒每个 VSync 上的 CPU,因此需要有一种机制来保留最后几次排队翻转的帧显示时间。

支持硬件翻转队列的图形驱动程序需要将每个活动 VidPnSource 的给定 MPO 平面的每个已完成或取消翻转的信息写入 OS 提供的翻转队列日志缓冲区。

OS 保证在针对每个活动 VidPnSource 的给定 MPO 平面进行第一次 DxgkDdiSetVidPnSourceAddress 调用之前,在调用 DxgkDdiSetFlipQueueLogBuff) er 时提供翻转队列日志指针 (。 当翻转队列没有任何未完成的请求时,允许 OS 销毁翻转队列日志缓冲区。 在这种情况下,它将在下一次 DxgkDdiSetVidPnSourceAddress 调用之前提供新的日志指针。 翻转队列日志是循环的。 写入 [NumberOfEntries-1] 项后,下一个日志条目将为 [0]。

完成一批排队翻转后,KMD 必须保证在以下两个时间点中最早更新已完成翻转的翻转队列日志:

翻转队列日志 DDI

添加了以下与翻转队列日志相关的回调和关联的结构:

KMD 在 DRIVER_INITIALIZATION_DATA 中提供指向其函数 指针。

VSync 中断结构更新

DXGKARGCB_NOTIFY_INTERRUPT_DATA 结构进行了以下更改,以便为硬件翻转队列模型实现 VSync 中断:

  • DXGK_INTERRUPT_CRTC_VSYNC_WITH_MULTIPLANE_OVERLAY3枚举值已添加为 InterruptType
  • CrtcVSyncWithMultiPlaneOverlay3 结构已添加到联合中。 CrtcVSyncWithMultiPlaneOverlay3 的语义类似于现有的 CrtcVSyncWithMultiPlaneOverlay2 结构,不同之处在于 ,CrtcVSyncWithMultiPlaneOverlay3.pMultiPlaneOverlayVSyncInfo 指向翻转队列日志中以前未报告的 PresentId 的范围。
  • CrtcVSyncWithMultiPlaneOverlay3pMultiPlaneOverlayVSyncInfo 成员添加了 DXGK_MULTIPLANE_OVERLAY_VSYNC_INFO3 结构。

再次使用 基本硬件翻转队列 示例图:

演示基本硬件翻转队列机制的示意图。

假设在提交翻转 N 时将 FirstFreeFlipQueueLogEntryIndex 设置为 40,然后完成 NN+1N+2 演示。

在单个平面配置分别在 v2、v3、v4 完成三个 PresentIds NN+1N+2 后,KMD 将在其翻转队列日志缓冲区中写入三个新条目,索引为 40、41 和 42。 KMD 报告 CrtcVSyncWithMultiPlaneOverlay3 结构中的 FirstFreeFlipQueueLogEntryIndex 值 43。 OS 将观察到 FirstFreeFlipQueueLogEntryIndex 从 40 更改为 43,并将从日志条目 40、41 和 42 读取。 KMD 需要设置以下翻转队列日志缓冲区值,如下所示:

  • VidPnTargetId:含义与 CrtcVSyncWithMultiPlaneOverlay2 中的含义相同

  • PhysicalAdapterMask:含义与 CrtcVSyncWithMultiPlaneOverlay2 中的含义相同

  • MultiPlaneOverlayVSyncInfoCount = 1

  • pMultiPlaneOverlayVSyncInfo[0]。LayerIndex = 0

  • pMultiPlaneOverlayVSyncInfo[0]。FirstFreeFlipQueueLogEntryIndex = 43

  • LogBufferAddressForPlane0[40]。PresentId = N

  • LogBufferAddressForPlane0[40]。PresentTimestamp = v2

  • LogBufferAddressForPlane0[41]。PresentId = N+1

  • LogBufferAddressForPlane0[41]。PresentTimestamp = v3

  • LogBufferAddressForPlane0[42]。PresentId = N+2

  • LogBufferAddressForPlane0[42]。PresentTimestamp = v4

显式翻转队列日志更新请求

在某些情况下,OS 需要获取有关最后一批已完成的翻转的信息,而无需等待 VSync 中断。 在这种情况下,OS 显式调用 DxgkDdiUpdateFlipQueueLog ,以请求 KMD 从其专有显示硬件数据结构读取,并将过去的翻转信息写入翻转队列日志。 日志的语义与前面所述的语义相同;唯一的更改是 FirstFreeFlipQueueLogEntryIndex 返回到 VSync 中断之外的 OS。

DxgkDdiUpdateFlipQueueLog 在设备中断级别 (DIRQL) 调用,它与 DxgkDdiSetVidPnSourceAddressWithMultiPlaneOverlay3 DDI 位于同一同步类中。

硬件翻转队列中存在排队翻转时显示模式更改和电源转换

Dxgkrnl 将确保在启动模式更改或关闭监视器之前完成或取消硬件翻转队列中已排队的翻转。

将 Present 请求映射到硬件翻转队列时间戳

在特定适配器上启用硬件翻转队列时,所有翻转调用都将附带时间戳。 换句话说,KMD 不需要混合处理新旧 DxgkDdiSetVidPnSourceAddress 语义。

OS 会自动将现有的基于间隔的演示 API 请求转换为对 KMD 的基于时间戳的翻转调用。 以下部分讨论各种情况,以及如何将这些情况映射到 KMD 接收的标志、 持续时间和时间戳的组合。

撕裂和非撕裂翻转语义

启用硬件翻转队列时,撕裂翻转的语义在概念上是相同的。 到达 TargetFlipTime 后,KMD 应提交翻转以显示,同时仍遵循 FlipImmediateFlipImmediateNoTearingFlipOnNextVSync 等标志。 换句话说,KMD 的行为应与 OS 在同一翻转标志和参数 的 TargetFlipTime 处提交翻转一样。

例如,如果 FlipOnNextVSync 设置为 1,并且 TargetFlipTime 位于框架中间,则此翻转应仅显示在下一个 VSync 上。

FlipOverwrite 支持和硬件翻转队列

硬件翻转队列是转覆盖功能的严格超集,由 DXGK_DRIVERCAPS 中的 MaxQueuedMultiPlaneOverlayFlipVSync 值控制。

因此,如果驱动程序通过将 MaxHwQueuedFlips 设置为大于 1 的值来选择加入硬件翻转队列,OS 将忽略 MaxQueuedMultiPlaneOverlayFlipVSync 值。

具有过期的 TargetFlipTime 的多次翻转

当给定 MPO 平面存在多个排队翻转和 过期的 TargetFlipTime 时,硬件显示队列必须选取最近排队的过期翻转并将其提交以显示。 其余过期的翻转应被视为已取消,相应的翻转队列日志条目应包含 DXGK_HWFLIPQUEUE_TIMESTAMP_CANCELLED 作为 PresentTimestamp 值。

Duration 和 TargetFlipTime 之间的交互

当屏幕上显示此结构中指定的翻转时,DXGKARG_SETVIDPNSOURCEADDRESSWITHMULTIPLANEOVERLAY3结构中的 Duration 参数应生效。 它为所有平面上的 VidPnSourceId 指定的输出指定新的所需显示刷新率行为。 在 WDDM 3.1 和 Windows 2022 版本中,为了简化不支持排队自定义 持续时间 更改的硬件的驱动程序实现,OS 仅在完成以前的翻转请求后提交具有新 Duration 参数的翻转请求。

将“演示间隔”映射到 TargetFlipTime

固定刷新速率时的映射间隔

若要保留现有间隔语义,OS 必须使用当前间隔和刷新率计算目标翻转时间。 但是,将目标翻转时间恰好设置为翻转应命中屏幕的预期 VSync 时间,如果实际 VSync 计时稍有偏差,则会导致由于错过的 VSync 而频繁出现故障。 为了防止故障,OS 会从计算的目标翻转时间中减去 VSync 间隔的一半。

下面是将当前间隔映射到目标翻转时间的简化公式:

TargetFlipTime = PreviousFlipStartVSyncTime + (PreviousFlipPresentInterval * FixedRefreshRate) - (FixedRefreshRate / 2)

存在虚拟刷新率 WDDM 2.9 功能的映射间隔

虚拟刷新速率功能可能会暂时将显示刷新率提高到当前刷新速率的整数倍 (即,24 Hz 可以提升到 144 Hz 或 192 Hz) 。 对于能够支持此提升的设备,将修改上一部分中的公式,以使用当前刷新速率的最快倍数:

TargetFlipTime = PreviousFlipStartVSyncTime + (PreviousFlipPresentInterval * FixedRefreshRate) - (FastestRefreshRate / 2)

将刷新率更改为非多数时的映射间隔

例如,当刷新速率更改为当前刷新速率 (从 24 Hz 更改为 60 Hz) 的非倍数时,OS 必须检查队列翻转,以确定计算的目标时间在新的刷新速率下是否仍然有效。 如果需要更改目标翻转时间,OS 将取消排队的翻转,并使用新计算的目标翻转时间重新排队。