【问题标题】:How many frames deep is a modern graphics pipeline?现代图形管道有多少帧深?
【发布时间】:2016-12-12 15:57:52
【问题描述】:

假设管道已满:GPU 等待 vsync,GPU/驱动程序命令缓冲区已满,因此用户程序被阻塞。

(现代)管道中有多少帧数据?

例如:(4)

  1. GPU 前端缓冲区中的帧
  2. GPU 后台缓冲区中的帧
  3. GPU 命令缓冲区中的帧
  4. CPU 驱动程序命令缓冲区中的帧

【问题讨论】:

    标签: opengl graphics directx metal vulkan


    【解决方案1】:

    这取决于您使用的是哪种显卡,以及您将其置于哪种模式,但一般来说,答案是 1-3 帧(或者 2-4,如果您计算的是作为帧被推入缓冲区)。

    • 如果没有 Vsync 或任何其他类型的双缓冲策略,则不会强制要求在任何给定时间在内存中保留超过 1 帧,并在新帧被推入缓冲区时立即被覆盖。李>
    • 启用 VSync 后,新帧被推入帧缓冲区的第二部分,并延迟任何未来命令的执行,直到“垂直同步”(因此得名)触发,此时两个帧翻转。
    • 第三种模式,OpenGL 不常见,但 Vulkan 和 DirectX 用户熟悉,称为“信箱模式”,有时也称为“三重缓冲”,保留两个“后台缓冲区”,总共三个缓冲区:
      • 其中一个后台缓冲区保留供垂直同步触发时使用。
      • 另一个后台缓冲区直接接收完成的帧,没有延迟
      • 每当发生垂直同步时,这两个后台缓冲区的角色就会切换。

    请注意,使用三重缓冲,当缓冲区已满时主机不会被阻塞。

    GPU 可能会选择缓冲额外的帧,就像在您的示例中一样,尽管这对 OpenGL/DirectX11- 比对 Vulkan/DirectX12+ 更常见,因为在后者的 API 中,主机在术语方面更加明确GPU应该做什么,我无法想象一个程序员会故意扩展帧缓冲区。除了 Triple Buffering 已经提供的功能之外,它还能提供什么好处还不是很清楚。

    【讨论】:

    • 好的。因此,根据经验,使用开启 vsync 的 OpenGL - 我注意到:(1)只要我能够在 32.2 毫秒内提交 2 个 CPU 帧(第一个需要 27 毫秒,第二个无关紧要)花了 3 毫秒) - 然后我观察到没有丢帧。 (2) 但是,如果不这样做,则会导致丢帧。关于平台的管道,我可以得出什么结论?
    • @user7226419 这是垂直同步的自然行为。如果第二帧进入甚至稍微超过垂直同步的截止点,GPU 将等到下一帧再呈现该帧。
    • 如果第一帧错过了截止时间,GPU 根本不会等待。我假设这是因为 GPU 能够显示的第一个帧之前已经在管道中的第 0 帧? IE。管道中至少有 1 个“潜在”帧?
    • @user7226419 可能。当然请记住,OpenGL 可以做很多“奇怪”的事情,因为它所代表的图形模型与现代 GPU 的工作方式大相径庭,以至于需要大量的 Driver Magic 才能使一切符合要求。
    【解决方案2】:

    对于传统 API(非命令缓冲区 API),唯一真正重要的是您使用了多少缓冲区。图形流水线可能是流水线的,但流水线并没有那么深,以至于多个完全独立的帧可以同时处于被处理的中间。所以 GPU 的队列和 GPU 本身通常只会处理一个帧。

    而且由于这些 API 中没有真正的方法来为多个完整帧构建命令数据,因此您可以在飞行中拥有的帧数将受到您使用的实际缓冲区数量的限制。延迟的帧数通常是缓冲区数 + 1,表示您正在构建的帧。

    对于命令缓冲区 API,帧数通常取决于您拥有多少 CPU 内存。缓冲区的数量提供了最低限度,但从技术上讲,没有什么可以阻止您提前缓冲数十或数百帧。在 CPU 内存之外。

    当然,这是假设您所有的每帧数据都存在于 CB 中。如果这些数据中有任何数据在 GPU 可访问的内存中(例如,矩阵数组等),或者您需要在帧之间更改描述符集,那么您现在需要缓冲另一组内容。这对事情的深度施加了额外的限制。

    【讨论】:

    • 感谢您的回复。我怎么知道我正在使用多少个缓冲区? (这是我的图形知识水平:P)例如,在我的项目中,我只设置了一个帧缓冲区。
    • @user7226419:在 OpenGL 中,您无法直接控制默认帧缓冲区中的缓冲区数量。因此,您是否可以计数并不重要。你不能用这些信息做任何事情。对于命令缓冲区 API,您需要特定数量的缓冲区。
    • 虽然无法控制缓冲区的数量,但一般有X个缓冲区吗?例如:用于 iOS、Android 上的 OpenGLES 2.0 实现。
    • 在 GLES 2.0 中,使用默认显示时,默认为两个缓冲区:正面和背面。在一个渲染周期之后,您的应用必须调用 eglSwapBuffer(display, surface) 来交换前后缓冲区。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-18
    • 2019-06-13
    • 2019-06-08
    相关资源
    最近更新 更多