提高显示性能

时间:2016-03-21 19:58:02

标签: python performance pygame

所以我一直在为我的游戏添加一些东西,在添加一个特定的东西后,游戏变得非常迟钝。我使用pygame.time.get_ticks()进行了一些测试,以查看在循环中花费的时间,并发现大约90%的时间花在了两个位置。 1.将所有精灵绘制到屏幕上。 2.绘制我的能力管理器,它只是绘制/显示一些图像。

在我的能力管理器中删除我的convert()和convert_alpha()显着改进性能时,我感到困惑,然后在绘制我的精灵时删除转换似乎不会影响性能。

任何人都知道为什么转换会降低速度,文档说这是最好的方法。另外,为什么它可能在一个领域而不是另一个领域有所帮助?

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

1 个答案:

答案 0 :(得分:1)

警告:我没有使用pygame但是我已经专业地编写了缩放器和转换器,用于高清视频,因此我正在绘制关于那次经历。

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

从那起:

  

如果没有传递参数,则新Surface将具有与显示Surface相同的像素格式。这总是最快的blitting格式。

换句话说,如果格式匹配,它会很快。但是,否则,它必须进行转换[运行速度较慢]。

  

最好在将所有Surface多次blit之前进行转换。

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

对于你的精灵,它们应该相对较小,所以差别不大。对于较大的区域,转换可能[并且似乎]很重要。

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

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

因此,再次,预先准备将是可行的方式。

如果由于源区域在每个帧上发生变化而无法做到这一点,则可能会引入一帧滞后并在多个线程/核心中进行转换,将整个区域细分为线程的子区域。

<强>更新

  

因此,您注意到,首先,速度会降低,因为必须更改像素格式。

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

专业游戏通过&#34; splash&#34;带有徽标的页面,可以进行[平凡的]动画(例如只是变形颜色等)

  

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

是的,它应该更快,基于你已经描述的内容:后续帧应该是45毫秒而不是80.现在给你的帧速率为22,这可能已经足够了。如果你仍然需要更快(即达到30 fps),那么我所提到的分区技术可能会有所帮助。此外,只有blitting从N帧到N + 1的变化也可能有所帮助。

  

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

下面是blit和转换的一些[粗略]代码(即仅用于说明 - 不是真正的代码)。

您现在正在做的事情就像下面的blit_convert 每个数据框架一样,我们会调用ability_manager_surface

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

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

# 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

注意:以上示例使用&#34;玩具&#34;转换功能。要进行高分辨率/高质量图像重新缩放(例如1024x768 - > 1920x1080),您可能需要使用/ select&#34;多相重采样&#34;而那个计算是惊人的。例如,仅针对笑脸,请参阅[令人难以置信的]:https://cnx.org/contents/xOVdQmDl@10/Polyphase-Resampling-with-a-Ra

更新#2:

  

发现只更新有用的内容的想法

这是对实时动画和图形的标准建议。只重新考虑你需要的东西。你只需要确定哪个是哪个。

  

但是,如果我读得正确,你说我的游戏在转换后会变慢,因为我每帧都会这样做。

根据您的原始描述,那将是/应该是这种情况。

  

情况并非如此,因为我一开始就转换,所以它应该是你谈论的快速blit,但如果我从来没有完全转换它会更快

如果没有您的实际代码,[对我来说]推测是很困难的。但是......

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

因此,如果您预先转换屏幕外表面,如果转换后的格式与屏幕格式匹配,为什么它会变慢[blit] 。如果它变慢,那么某处就会出现不匹配的情况。而且,如果您使用默认值创建曲面,为什么需要转换?

标准型号是尽可能直接在屏幕上进行操作。屏幕是&#34;双重缓冲&#34;并且在主显示循环的底部使用pygame.display.flip完成实际渲染。

所以,我不确定你的程序中表面转换的位置。

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

这只是来自网络搜索的一个链接&#34;所有单词&#34; for&#34; pygame示例程序&#34;。因此,如果您能够比较您正在对他们做的事情,上述链接[以及其他人]可能会对您有所帮助。