我最近从 https://github.com/fogleman/Craft 下载了fogleman 出色的“500 行中的我的世界”演示。我使用了 2to3 工具并手动更正了一些细节,使其可以在 python3 下运行。我现在想知道在 render 方法中调用 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 专家,所以我很感谢大家的建议。 ;)
最佳答案
你的图表是错误的。好吧,至少它不是用于衡量性能的合适图表。永远不要相信 gl*
函数会在您告诉它时执行,也永远不要相信它执行得像您期望的那样快。
大多数 gl*
函数不会立即执行,也不可能立即执行。请记住,我们正在处理 GPU,告诉它直接做事很慢。因此,相反,我们为 GPU 编写了一个待办事项列表(一个命令队列),并在我们真正需要 GPU 输出某些内容时将其转储到 VRAM 中。这个“转储”是同步过程的一部分,我们可以用 glFlush
触发一个。尽管如此,OpenGL 是用户友好的(至少与 Vulkan 相比),因此它不依赖于我们明确地刷新命令队列。许多 gl*
函数(完全取决于您的图形驱动程序)将隐式同步 CPU 和 GPU 状态,其中包括刷新。
由于 glClear
通常会启动一个帧,因此您的驱动程序可能认为执行这种隐式同步会很好。正如您可能想象的那样,同步是一个非常缓慢的过程,它会阻塞 CPU 执行直到它完成。
这可能就是这里发生的事情。同步过程的一部分是执行内存事务(如 glBufferData
、 glTexImage*
),这些事务可能会排队等待,直到它们被您的 glClear
调用刷新。这在你的例子中是有道理的;我们可以观察到的峰值可能是您上传了大量块数据后的帧。
但请记住,这只是纯粹的猜测,我也不是这类东西的完全专家,所以不要相信我的确切细节。 OpenGL wiki 上的 This page 是这类事情的好资源。
尽管有一件事是肯定的,但您的 glClear
调用并没有您的分析器所说的那么长。您应该使用专用于分析图形的分析器。
关于Python minecraft pyglet glClear() 跳帧,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38699416/