【问题标题】:Python minecraft pyglet glClear() skipping framesPython minecraft pyglet glClear() 跳帧
【发布时间】:2016-08-01 12:51:55
【问题描述】:

我最近从https://github.com/fogleman/Craft 下载了fogleman 出色的“Minecraft in 500 lines”演示。我使用了 2to3 工具并手动修正了一些细节,使其可以在 python3 下运行。我现在想知道在渲染方法中调用self.clear() 的事情。这是我修改后的渲染方法,每帧都被 pyglet 调用:

def on_draw(self):
    """ Called by pyglet to draw the canvas.

    """
    frameStart = time.time()
    self.clear()
    clearTime = time.time()
    self.set_3d()
    glColor3d(1, 1, 1)
    self.model.batch.draw()
    self.draw_focused_block()
    self.set_2d()
    self.draw_label()
    self.draw_reticle()
    renderTime = time.time()

    self.clearBuffer.append(str(clearTime - frameStart))
    self.renderBuffer.append(str(renderTime - clearTime))

如您所见,我采用了self.clear() 的执行时间和渲染方法的其余部分。 self.clear()的调用调用了pyglet的这个方法,可以在.../pyglet/window/__init__.py找到:

def clear(self):
    '''Clear the window.

    This is a convenience method for clearing the color and depth
    buffer.  The window must be the active context (see `switch_to`).
    '''
    gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)

所以我基本上会打电话给glClear()
我在测试游戏时注意到一些帧丢失(60 FPS),所以我添加了上面的代码来测量命令的执行时间,尤其是glClear() 的执行时间。我发现渲染本身永远不会超过 10 毫秒。但是glClear() 的持续时间有点不同,这里是不同条件下 3 次测量的分布:
Duration of glClear() under different conditions.

洋红色线显示一帧的时间限制。所以第一行后面的所有内容都意味着有丢帧。
glClear() 的执行时间在第一帧到期后似乎有某种“回声”。你能解释一下为什么吗?我怎样才能更快地拨打电话?
不幸的是,我不是 OpenGL 专家,所以我很感谢大家的建议。 ;)

【问题讨论】:

  • 可能是您的计时器分辨率仅为 16 毫秒,这可以解释“回声”。请参阅docs.python.org/2/library/time.html#time.time,其中说“并非所有系统都提供比 1 秒更好的精度。”。尝试不同的计时器,看看是否重要。

标签: python opengl frame minecraft pyglet


【解决方案1】:

你的图表是错误的。好吧,至少它不是用于衡量性能的合适图表。永远不要相信 gl* 函数会在你告诉它时执行,也不要相信它会像你期望的那样快速执行。

大多数gl* 函数不会立即执行,它们不可能。请记住,我们正在与 GPU 打交道,告诉它直接执行操作很慢。因此,相反,我们为 GPU 编写了一个待办事项列表(一个命令队列),并在我们真的需要 GPU 输出某些内容时将其转储到 VRAM。这个“转储”是称为同步的过程的一部分,我们可以使用glFlush 触发一个。不过,OpenGL 是用户友好的(至少与 Vulkan 相比),因此它不依赖于我们显式刷新命令队列。许多 gl* 函数,完全取决于您的图形驱动程序,将隐式同步 CPU 和 GPU 状态,其中包括刷新。

由于glClear 通常会启动一个帧,因此您的驱动程序可能认为执行这种隐式同步会很好。正如您可能想象的那样,同步是一个非常缓慢的过程,并且在完成之前会阻塞 CPU 执行。

这可能就是这里发生的事情。同步过程的一部分是执行内存事务(如glBufferDataglTexImage*),这些事务可能会排队,直到它们被您的glClear 调用刷新。在您的示例中这是有道理的;我们可以观察到的峰值可能是您上传大量区块数据后的帧。

但请记住,这只是纯粹的猜测,我也不是这类事情的专家,所以不要相信我的确切细节。 OpenGL wiki 上的This page 是这类事情的好资源。

尽管有一件事是肯定的,但您的glClear 调用并不需要您的分析器所说的时间。您应该使用专用于分析图形的分析器。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-18
    • 1970-01-01
    • 2012-06-20
    • 1970-01-01
    • 1970-01-01
    • 2021-07-16
    • 1970-01-01
    • 2015-12-31
    相关资源
    最近更新 更多