2014-12-02 116 views
1

OpenGL wiki on Performance,它说:OpenGL:哪些OpenGL实现不流水?

“OpenGL实现几乎都是流水线 - 也就是说, 的事情,当你告诉OpenGL吸引他们并不一定按 - 和一个OpenGL调用返回的事实并不意味着它完成了 渲染。“

既然它说“差不多”,那就意味着有些实现不是流水线的。

在这里,我找到一个: OpenGL Pixel Buffer Object (PBO)

“常规glReadPixels()会阻塞管道,并等待,直到所有 像素数据传输然后,返回控制到 应用相反,glReadPixels。 ()与PBO可以安排 异步DMA传输,并立即返回而不会失速 因此,应用程序(CPU)可以立即执行其他进程, ,同时通过OpenGL(GPU)与DMA传输数据。

所以这意味着传统的glReadPixels()(不与PBO)阻塞管道。 但实际上在glReadPixels的OpenGL引用中,我不能说出这个事实。我想知道: 哪些OpenGL实现不流水线?

glDrawArrays怎么样?

+0

不是100%确定,但我认为所有不返回任何内容的操作都是流水线操作。例如glDrawArrays是流水线,而glGenBuffers不是。 – dari 2014-12-02 22:28:59

回答

2

OpenGL规范本身并未指定术语“管道”,而是“命令流”。命令流执行的运行时行为是故意保持开放的,从而为实现者提供最大的灵活性。

的重要术语是 “OpenGL的sychronization点”:https://www.opengl.org/wiki/Synchronization

在这里,我找到一个:(链接到songho文章)

请注意,这不是一个官方的OpenGL规范的资源。 “封锁OpenGL管道”的措辞有点不幸,因为它实际上阻止了瓶颈,瓶颈变成了“颠倒”。实际上,它意味着,只有在执行完所有将要读取图像的命令后,glReadPixels才能返回。

所以这意味着传统的glReadPixels()(不与PBO)阻塞管道。但实际上在glReadPixels的OpenGL参考中,我无法说出这个事实。

事实上,它不是被阻塞的OpenGL管道,而是CPU上程序的执行。这意味着,GPU看不到来自CPU的更多命令。所以管道不会“堵塞”,但实际上已经耗尽。当管道流失或需要重新启动时,有人说管道已经停滞(即管道中的流量停止)。

从GPU的角度来看,所有事情都会发生在最大吞吐量的情况下:渲染东西直到glReadPixels被调用点,进行DMA传输,不幸的是在启动传输后没有其他命令可用。

glDrawArrays怎么样?

glDrawArrays在数据排队并且必要时立即返回。

+0

“所以管道不会”堵塞“,但实际上已经耗尽。”当我在glReadPixels()之后在CPU中设置时钟时,时钟记录是什么时间? – user1914692 2014-12-02 23:23:37

+0

@ user1914692:这真的取决于OpenGL的实现。假设你做了一些像'draw_something(); glfinish在(); clock_gettime(CLOCK_MONOTONIC,&start); glReadPixels(&cpumem); clock_gettime(CLOCK_MONOTONIC,&end);''你将设置裸转移和格式转换时间。但是,如果你做了类似'draw_something(); clock_gettime(CLOCK_MONOTONIC,&start); glReadPixels(&cmpumem); clock_gettime(CLOCK_MONOTONIC,&end);'缺少glFinish),你会得到一个明显更长的持续时间,原因是glReadPixels意味着一个同步,并且必须等待完成 – datenwolf 2014-12-03 00:43:00

+0

@ user1914692:**但是**如果您将glReadPixels添加到PBO,CPU (); glFinish(); glBindBuffer(GL_PIXEL_PACK_BUFFER,...); clock_gettime(CLOCK_MONOTONIC,&start); glReadPixels(); clock_gettime(CLOCK_MONOTONIC,&end););不需要等待glReadPixels完成。和glFinish:'draw_something(); glBindBuffer(GL_PIXEL_PACK_BUFFER,...); clock_gettime(CLOCK_MONOTONIC,&start); glReadPixels(); clock_gettime(CLOCK_MONOT ONIC,&end);'会相反,因为没有什么需要等待完成。 – datenwolf 2014-12-03 00:45:58

1

实际上它意味着这个特定的操作不能被流水线化,因为所有的数据都需要在函数返回之前被传输,这并不意味着其他东西不能。

这样的操作据说是档位的流水线。一个会使管道失速的功能是glFinish

通常,当函数返回一个像获取缓冲区内容那样的值时,它会导致失速。

取决于驱动程序的实现创建程序和缓冲区等,可以做到没有拖延。

+1

'glFlush()'只提交待处理的工作,它不会等待它完成。你可能会想'glFinish()'。 – 2014-12-02 22:38:24

0

然后我想知道:哪些OpenGL实现不流水线?

我可以想象一个纯粹的软件实现可能不是流水线。如果您最终在同一个CPU上执行它,没有太多理由排队工作。除非你想利用多线程。

但可以肯定地说,任何使用专用硬件(通常称为GPU)的OpenGL实现都将被流水线化。这允许CPU和GPU并行工作,这对于获得良好的系统性能至关重要。而且,向GPU提交工作会产生一定的开销,因此排队工作并将其提交到更大批次是有益的。

但实际上在OpenGL的glReadPixels引用中我不能说出这个事实。

是的。手册页不直接指定哪些调用会导致同步。一般来说,任何返回GPU生成的值/数据都会导致同步。想到的例子:

  • glFinish()。显式地要求完全同步,这实际上是它的唯一目的。
  • glReadPixels(),在非PBO的情况下。 GPU必须先完成渲染,然后才能读回结果。
  • glGetQueryObjectiv(id, GL_QUERY_RESULT, ...)。阻止,直到GPU达到提交查询的点。
  • glClientWaitSync()。等待GPU到达提交相应的glFenceSync()的点。

请注意,可能有不同类型的同步不直接绑定到特定的OpenGL调用。例如,在整个工作负载受GPU限制的情况下,除非有一些节流,否则CPU会排队工作。因此,驱动程序会在多或少的任意点阻塞CPU,让GPU赶上某个特定点。这可能发生在框架边界,但它不一定是。如果内存不足,或内部驱动程序资源耗尽,则可能需要进行类似的同步。