提高显示性能



所以我一直在游戏中添加一些东西,在添加了一个特定的东西之后,游戏变得相当滞后。我用pygame.time.get_ticks()做了一些测试,看看时间在循环中花在了哪里,发现大约90%的时间花在了两个位置。1.把我所有的精灵都画到屏幕上。2.绘制我的能力管理器,它只是绘制/闪电打印一些图像。

当我在能力管理器中删除convert()和convert_alpha()显著提高了的性能时,我感到困惑,然后在绘制精灵时删除convert似乎不会影响性能。

任何人都知道为什么转换可能会减慢速度,医生说这是最好的方法。此外,为什么它可能在一个领域有所帮助,而在另一个领域却没有?

编辑:一些数字显示我的测试。删除能力管理器绘图#2的转换,将绘制转换的平均时间从大约80毫秒减少到大约45毫秒。删除或添加#1的转换,在屏幕上绘制精灵,几乎不会影响做事的时间。影响范围从+或-5。这个小变化可能不是移除转换的结果,所以我的问题应该主要集中在"为什么移除转换在能力管理器绘图中有这么大帮助?",而只关注为什么它可能在一个领域有这么大的帮助,而不是在另一个领域。

注意:我不使用pygame,但我专业地为高清视频编写了缩放器和转换器,所以我借鉴了这一经验。

我确实在这里查阅了文档:http://www.pygame.org/docs/ref/surface.html#pygame.Surface.convert

来自:

如果未传递任何参数,则新曲面将具有与显示曲面相同的像素格式。这始终是闪电战最快的格式。

换句话说,如果格式匹配,它会运行得很快。但是,否则,它必须进行转换(这将运行得更慢)。

最好在对所有曲面进行多次闪电扫描之前对其进行转换。

这可能是您想要做的(即保留与最终输出格式匹配的后转换表面的缓存副本)

对于你的精灵来说,它们应该相对较小,所以差别不大。对于更大的区域,转换可能[而且似乎]意义重大。

转换必须逐像素进行,而不是简单的blit(可以用一系列快速[C]memcpy操作来完成)。这可能涉及使用周围像素的卷积内核[对于一个好的缩放器,我看到使用了2D 6抽头FIR滤波器]。

由于精灵较小,转换器可能会选择更简单的转换算法,因为失真不太明显。对于较大的面积,转换器可以选择更复杂的算法,因为失真将在较大的面积上累积。

因此,再次强调,预先做好准备是可行的。

如果你不能做到这一点,因为源区域在每一帧上都会发生变化,你可能会引入一帧延迟,并在多个线程/核心中进行转换,将整个区域细分为线程之间的子区域。


更新:

因此,您注意到,一开始,由于像素格式必须更改,速度会降低。

游戏开始时的预计算应该不是问题,因为你的数字是80毫秒。用户甚至不会注意到启动游戏的微小延迟。

专业游戏用带有其标志的"飞溅"页面来掩盖这一点,该页面可能会制作[琐碎]动画(例如,只改变颜色等)

但在游戏开始时转换后,其他人的速度不应该更好吗?

是的,根据您已经描述的内容,它应该更快:后续帧应该是45毫秒,而不是80毫秒。现在,你可以得到22的帧速率,这可能已经足够了。如果你仍然需要更快(即达到30帧/秒),那么使用我已经提到的分区技术可能会有所帮助。此外,仅对从第N帧变为N+1帧的内容进行闪电传输也可能有所帮助。

我仍然很困惑,为什么如果我转换,整个游戏的速度会变慢。

下面是blit和convert的一些[粗略]代码(即,只是为了说明——而不是真实的代码)。

您现在所做的操作类似于下面的blit_convert,用于数据上的每个帧,我们称之为ability_manager_surface

请注意,它比简单的blit(例如下面的blit_fastblit_slow)慢。快速blit只是将每个源像素复制到目标像素。采样转换器必须取当前源像素及其最近邻居的平均值,因此它必须为每个目标像素获取五个源像素值。因此,速度较慢。真正的缩放算法可能更慢。

如果在ability_manager_surface上启动游戏期间执行blit_convert,并将输出保存到"已转换"变量(例如precalc_manager_surface),则可以使用precalc_manager_surface在每帧上使用blit_fast。也就是说,不需要重新计算"静态"数据。

# dstv -- destination pixel array
# dsthgt -- destination height
# dstwid -- destination width
#
# dstybase -- destination Y position for upper left corner of inset
# dstxbase -- destination X position for upper left corner of inset
#
# srcv -- source pixel array
# srchgt -- source height
# srcwid -- source width
# ------------------------------------------------------------------------------
# blit_fast -- fast blit
# this uses a 1 dimensional array to be fast
def blit_fast(dstv,dsthgt,dstwid,dstybase,dstxbase,srcv,srchgt,srcwid):
# NOTE: I may have messed up the equations here
for yoff in range(dstybase,dstybase + srchgt):
dstypos = (yoff * dstwid) + dstxbase
srcypos = (yoff * srcwid);
for xoff in range(0,srcwid):
dstv[dstypos + xoff] = srcv[srcypos + xoff]
# ------------------------------------------------------------------------------
# blit_slow -- slower blit
# this uses a 2 dimensional array to be more clear
def blit_slow(dstv,dsthgt,dstwid,dstybase,dstxbase,srcv,srchgt,srcwid):
for yoff in range(0,srchgt):
for xoff in range(0,srcwid):
dstv[dstybase + yoff][dstxbase + xoff] = srcv[yoff][xoff]
# ------------------------------------------------------------------------------
# blit_convert -- blit with conversion
def blit_convert(dstv,dsthgt,dstwid,dstybase,dstxbase,srcv,srchgt,srcwid):
for yoff in range(0,srchgt):
for xoff in range(0,srcwid):
dstv[dstybase + yoff][dstxbase + xoff] = convert(srcv,yoff,xoff)
# convert -- conversion function
# NOTE: this is more like a blur or soften filter
# the main point is this takes _more_ time than a simple blit
def convert(srcv,ypos,xpos):
# we ignore the special case for the borders
cur = srcv[ypos][xpos]
top = srcv[ypos - 1][xpos]
bot = srcv[ypos + 1][xpos]
left = srcv[ypos][xpos - 1]
right = srcv[ypos][xpos + 1]
# do a [sample] convolution kernel
# this equation probably isn't accurate -- just to illustrate something that
# is computationally expensive on a per pixel basis
out = (cur * 0.6) + (top * 0.1) + (bot * 0.1) + (left * 0.1) + (right * 0.1)
return out

注意:上面的例子使用了一个"toy"转换函数。要进行高分辨率/高质量的图像重新缩放(例如1024x768-->1920x1080),您可能需要使用/选择"多相重新采样",其计算量非常大。例如,只是为了咧嘴笑,请参阅[令人难以置信]:https://cnx.org/contents/xOVdQmDl@10/多相再采样,带a-Ra


更新#2:

发现只更新移动有帮助的的东西的想法

这是实时动画和图形的标准建议。只需要重新计算你需要的。你只需要确定哪个是哪个。

然而,如果我读对了,你会说我的游戏在转换后变慢了,因为我每帧都这样做。

根据您最初的描述,情况应该是这样的。

事实并非如此,因为我在一开始就转换了,所以这应该是你所说的快速闪电战,但如果我从不转换,它会更快

如果没有实际的代码,[我]很难推测。但是

创建曲面时(例如,保存像.png这样的图像文件),默认格式是使用与屏幕格式非常匹配的格式。因此,它可以在不进行转换的情况下进行闪电传输。

那么,如果你预先转换了一个屏幕外的表面,如果转换后的格式与屏幕格式匹配,为什么它会更慢。如果速度慢一点,就会有不匹配的地方。而且,如果使用默认值创建曲面,为什么需要转换?

标准模式是尽可能直接在屏幕上进行操作。屏幕是"双缓冲"的,实际渲染是用主显示循环底部的pygame.display.flip完成的。

所以,我不确定曲面转换在程序中的作用。

下面是一些示例程序的链接[包括一些带有精灵的程序]:http://www.balloonbuilding.com/index.php?chapter=example_code

这只是"pygame示例程序"的"所有单词"网络搜索中的一个链接。因此,如果你能够将你所做的事情与他们进行比较,上面的链接[加上其他链接]可能会对你有所帮助。

最新更新