与 pygame 相比,为什么 pyglet 这么慢? [英] Why is pyglet so slow compared to pygame?

查看:90
本文介绍了与 pygame 相比,为什么 pyglet 这么慢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是代码.5000 个弹跳旋转的红色方块.(16x16 png) 在 pygame 版本上,我获得 30 fps,但使用 pyglet 获得 10 fps.对于这种事情,OpenGl 不应该更快吗?

Here is the code. 5000 bouncing spinning red squares. (16x16 png) On the pygame version I get 30 fps but 10 fps with pyglet. Isnt OpenGl supposed to be faster for this kind of thing?

pygame 版本:

import pygame, sys, random
from pygame.locals import *
import cProfile

# Set FPS
FPS = 60.0
clock = pygame.time.Clock()

# Set window
WINDOWWIDTH= 800
WINDOWHEIGHT = 600

pygame.init()
screen = pygame.display.set_mode((WINDOWWIDTH,WINDOWHEIGHT))

screen.fill((0,0,0))
background = screen.copy().convert()
image = pygame.image.load("square.png").convert()

class Square(object):
    def __init__(self,x,y):
        self.x = x
        self.y = y
        self.v_x = random.randint(1,100)
        self.v_y = random.randint(1,100)
        self.v_r = random.randint(-100,100)
        self.rotation = 0

    def __rep__(self):
        return "Square %d,%d"%(self.x,self.y)

    def update(self,dt):
        if self.x > WINDOWWIDTH:
            self.v_x *= -1
        elif self.x < 0:
            self.v_x *= -1
        if self.y > WINDOWHEIGHT:
            self.v_y *= -1
        elif self.y < 0:
            self.v_y *= -1

        self.x += self.v_x * dt
        self.y += self.v_y * dt
        self.rotation += self.v_r * dt

    def draw(self):
        screen.blit(pygame.transform.rotate(image,self.rotation),(self.x,self.y))


sqrs = []
for _ in range(5000):
    sqrs.append( Square(random.randint(0,WINDOWWIDTH-1),random.randint(0,WINDOWHEIGHT-1)) )


def main_loop():
    tick = 0.0
    elapsed = 0.0

    while elapsed < 10.0:
        dt = tick/1000.0
        # Events
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                sys.exit()

        # Logic
        for s in sqrs:
            s.update(dt)

        # Drawing
        screen.blit(background,(0,0))
        for s in sqrs:
            s.draw()

        pygame.display.update()
        pygame.display.set_caption('test program FPS: %s'%(clock.get_fps() ) )
        tick = clock.tick(FPS)
        elapsed += tick/1000.0
    pygame.quit()

cProfile.run("main_loop()")
i = input("...")

pyglet 版本:

import cProfile
import pyglet, random
# Disable error checking for increased performance
pyglet.options['debug_gl'] = False

from pyglet import clock

clock.set_fps_limit(60)

WINDOWWIDTH = 800
WINDOWHEIGHT = 600
FPS = 60.0

batch = pyglet.graphics.Batch()
window = pyglet.window.Window(WINDOWWIDTH,WINDOWHEIGHT)
fps_display = pyglet.clock.ClockDisplay()

image = pyglet.resource.image("square.png")

class Square(pyglet.sprite.Sprite):
    def __init__(self,x,y):
        pyglet.sprite.Sprite.__init__(self,img = image,batch=batch)
        self.x = x
        self.y = y
        self.v_x = random.randint(1,100)
        self.v_y = random.randint(1,100)
        self.v_r = random.randint(-100,100)

    def update(self,dt):
        if self.x > WINDOWWIDTH:
            self.v_x *= -1
        elif self.x < 0:
            self.v_x *= -1
        if self.y > WINDOWHEIGHT:
            self.v_y *= -1
        elif self.y < 0:
            self.v_y *= -1

        self.x += self.v_x * dt
        self.y += self.v_y * dt
        self.rotation += self.v_r * dt

sqrs = []
for _ in range(5000):
    sqrs.append( Square(random.randint(0,WINDOWWIDTH-1),random.randint(0,WINDOWHEIGHT-1)) )

elapsed = 0.0

def update(dt):
    global elapsed
    elapsed += dt
    if elapsed >= 10.0:
        clock.unschedule(update)
        window.close()
    else:
        for s in sqrs:
            s.update(dt)

@window.event
def on_draw():
    window.clear()
    batch.draw()
    fps_display.draw()


clock.schedule_interval(update, 1.0/FPS)

if __name__ == '__main__':
    cProfile.run("pyglet.app.run()")
    c = input("...")

pygame 的 cProfile 结果:

cProfile result for pygame:

         5341607 function calls in 9.429 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    9.429    9.429 <string>:1(<module>)
  1335000    2.259    0.000    2.259    0.000 pygame-test.py:32(update)
  1335000    1.323    0.000    5.969    0.000 pygame-test.py:46(draw)
        1    0.772    0.772    9.429    9.429 pygame-test.py:55(main_loop)
        1    0.000    0.000    9.429    9.429 {built-in method exec}
      267    0.020    0.000    0.020    0.000 {built-in method get}
        1    0.237    0.237    0.237    0.237 {built-in method quit}
  1335000    3.479    0.000    3.479    0.000 {built-in method rotate}
      267    0.013    0.000    0.013    0.000 {built-in method set_caption}
      267    0.067    0.000    0.067    0.000 {built-in method update}
  1335267    1.257    0.000    1.257    0.000 {method 'blit' of 'pygame.Surface' objects}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
      267    0.000    0.000    0.000    0.000 {method 'get_fps' of 'Clock' objects}
      267    0.001    0.000    0.001    0.000 {method 'tick' of 'Clock' objects}

Pyglet cProfile 输出:- 很长,这是部分输出,完整版这里.

Pyglet cProfile output: - Very long, this is partial output, full version here.

         9982775 function calls (9982587 primitive calls) in 10.066 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
      123    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:1596(_handle_fromlist)
        1    0.000    0.000   10.067   10.067 <string>:1(<module>)
       11    0.000    0.000    0.000    0.000 __init__.py:1055(_ensure_string_data)
       11    0.000    0.000    0.000    0.000 __init__.py:1061(_get_gl_format_and_type)
       58    0.000    0.000    0.000    0.000 __init__.py:1140(clear)
       75    0.000    0.000    0.012    0.000 __init__.py:1148(dispatch_event)
        1    0.000    0.000   10.067   10.067 __init__.py:115(run)
   ...
        1    0.000    0.000    0.000    0.000 lib.py:124(decorate_function)
     1108    0.005    0.000    0.005    0.000 lib_wgl.py:80(__call__)
   285000    1.409    0.000    9.872    0.000 pyglet-test.py:29(update)
       58    0.105    0.002    9.982    0.172 pyglet-test.py:49(update)
   ...
   855000    5.436    0.000    7.551    0.000 sprite.py:378(_update_position)
   285000    0.172    0.000    2.718    0.000 sprite.py:441(_set_x)
   851800    0.177    0.000    0.177    0.000 sprite.py:445(<lambda>)
   285000    0.174    0.000    2.670    0.000 sprite.py:451(_set_y)
   851115    0.155    0.000    0.155    0.000 sprite.py:455(<lambda>)
   285000    0.182    0.000    2.692    0.000 sprite.py:461(_set_rotation)
   285000    0.051    0.000    0.051    0.000 sprite.py:465(<lambda>)
   ...
     4299    0.007    0.000    0.025    0.000 vertexattribute.py:308(get_region)
        1    0.000    0.000    0.000    0.000 vertexattribute.py:380(__init__)
      116    0.000    0.000    0.000    0.000 vertexattribute.py:384(enable)
      116    0.000    0.000    0.000    0.000 vertexattribute.py:387(set_pointer)
        1    0.000    0.000    0.000    0.000 vertexattribute.py:461(__init__)
      116    0.000    0.000    0.000    0.000 vertexattribute.py:466(enable)
      116    0.000    0.000    0.000    0.000 vertexattribute.py:469(set_pointer)
        1    0.000    0.000    0.000    0.000 vertexattribute.py:501(__init__)
      116    0.000    0.000    0.000    0.000 vertexattribute.py:508(enable)
      116    0.000    0.000    0.000    0.000 vertexattribute.py:511(set_pointer)
        3    0.000    0.000    0.000    0.000 vertexbuffer.py:293(__init__)
      348    0.000    0.000    0.001    0.000 vertexbuffer.py:311(bind)
      348    0.000    0.000    0.001    0.000 vertexbuffer.py:314(unbind)
        3    0.000    0.000    0.000    0.000 vertexbuffer.py:381(__init__)
      348    0.001    0.000    0.004    0.000 vertexbuffer.py:388(bind)
     4299    0.006    0.000    0.016    0.000 vertexbuffer.py:420(get_region)
        3    0.000    0.000    0.000    0.000 vertexbuffer.py:424(resize)
     4299    0.002    0.000    0.002    0.000 vertexbuffer.py:460(__init__)
   855232    0.735    0.000    1.053    0.000 vertexbuffer.py:466(invalidate)
   ...
   855058    0.687    0.000    1.762    0.000 vertexdomain.py:581(_get_vertices)
   ...
     4300    0.002    0.000    0.002    0.000 {built-in method POINTER}
   ...
   841451    0.162    0.000    0.162    0.000 {built-in method cos}
   ...
2417/2415    0.000    0.000    0.000    0.000 {built-in method len}
   855489    0.142    0.000    0.142    0.000 {built-in method max}
   855469    0.176    0.000    0.176    0.000 {built-in method min}
  465/407    0.000    0.000    0.000    0.000 {built-in method next}
   ...
   841451    0.072    0.000    0.072    0.000 {built-in method radians}
       62    0.000    0.000    0.000    0.000 {built-in method setattr}
   841451    0.120    0.000    0.120    0.000 {built-in method sin}
   ...

推荐答案

Pyglet 图像(和精灵)可以围绕任意锚点旋转.如果您查看 pyglet/sprite.py,您会发现这是使用 Python 数学模块完成的,这就是它相当慢的原因.通过使用 OpenGL glRotate 甚至顶点着色器旋转精灵,这里似乎有优化的空间.

Pyglet images (and sprites) can be rotated around an arbitrary anchor. If you look at pyglet/sprite.py, you will see that this is done using the Python math module, which is why it's rather slow. It would seem there is room for optimiziation here, by rotating sprites using OpenGL glRotate or even a vertex shader.

这篇关于与 pygame 相比,为什么 pyglet 这么慢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆