OpenGL程序中的计时?

Timing in OpenGL program?

我已经学够了 OpenGL/GLUT(使用 PyOpenGL)来想出一个简单的程序来设置片段着色器、绘制全屏四边形并生成与显示同步的帧(shadertoy 风格).我在某种程度上也了解图形管道。

我不明白的是OpenGL程序和图形管线是如何配合在一起的。特别是,在我的 GLUT 显示回调中,

# set uniforms
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)  # draw quad
glutSwapBuffers()

我想我通过 glDrawArrays 给它顶点来激活顶点着色器,这会产生片段(像素)。但是,片段着色器会在 glDrawArrays 之后立即启动吗?有碎片,所以它可以做一些事情。另一方面,仍然有可能有更多的绘制命令创建更多的顶点,这可以 a) 产生新的片段和 b) 覆盖现有的片段。

我分析了程序,发现 99% 的时间花在了 glutSwapBuffers 上。这当然部分是由于等待垂直同步,但当我使用一个非常苛刻的片段着色器显着降低帧速率时,它会保持这种状态。这表明片段着色器仅在 glutSwapBuffers 的某处激活。对吗?

我知道片段着色器是在 GPU 上执行的,而不是 CPU,但它仍然显示 CPU(程序)等待 GPU(着色器)完成,在glutSwapBuffers...

I profiled the program and found that 99% of the time is spent in glutSwapBuffers. That is of course partially due to waiting for the vertical sync, but it stays that way when I use a very demanding fragment shader which significantly reduces the frame rate. That suggests that the fragment shader is only activated somewhere in glutSwapBuffers. Is that correct?

没有。这种逻辑是完全错误的。这里的要点是片段着色器 在 GPU 上运行,它与 CPU 完全异步。你不是在测量片段着色器,你是在测量一些隐式的 CPU-GPU-synchronization - 看起来你的实现在缓冲区交换上同步(如果排队的帧太多,可能),所以你测量的只是时间 CPU 必须等待 GPU。如果您在不显着增加 CPU 工作负载的情况下增加 GPU 工作负载,您的 CPU 只会花费更多时间等待。

OpenGL本身并没有定义任何这些,所以所有的细节最终都是完整的implementation-specific。规范只是保证实现的行为就像片段是按照您绘制基元的顺序生成的一样(例如,启用混合后,实际顺序成为相关的 evan 离子透支场景)。但是片段将在什么时候生成,哪些优化可能会发生 in-between 顶点处理和片段着色器的调用,完全不受您的控制。 GPU 可能会采用 tile-based 光栅化方案,其中实际片段着色会稍微延迟(如果可能)以提高效率并避免过度着色。

请注意,大多数 GPU 驱动程序完全异步工作。当您调用 gl*() 命令时,它 returns 在它被处理之前。它可能只会排队等候稍后处理(例如在另一个驱动程序线程中),并最终会在一些 GPU-specific 命令缓冲区中进行转换,然后传输到 GPU。您可能会以隐式 CPU-GPU 同步(或 CPU-CPU 与驱动程序线程)结束,例如,当您在绘制调用后读回帧缓冲区数据时,这将意味着所有先前的 GL 命令都将被刷新进行处理,CPU 将等待处理完成后再检索图像数据 - 这也是导致此类回读如此缓慢的原因。

因此,OpenGL 代码的任何 CPU-side 措施都是完全没有意义的。您需要在 GPU 上测量时间 ,这就是 Timer Queries 的用途。