2013-11-05 9 views
7

Ecco il codice. 5000 rimbalzando quadrati rossi rotanti. (16x16 png) Nella versione pygame ottengo 30 fps ma 10 fps con pyglet. OpenGl dovrebbe essere più veloce per questo genere di cose?Perché Pyglet è così lento rispetto a Pygame?

versione Pygame: versione

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("...") 

risultato Cprofile per 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 uscita: - molto lungo, questo viene emesso parziale, pieno versione 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} 
    ... 
+0

Qual è 'ingresso (...)' su pyglet? – ninMonkey

+0

L'input() in python standard. 'foo = input ('Prego inserire un valore:')' –

risposta

2

Il collo di bottiglia è in rotazione sprite pyglet. Se commentate la linea 'self.rotation' nel metodo Square update(), i vostri fps saranno quasi il doppio.

2

immagini pyglet (e) sprite possono essere ruotati intorno ad un ancoraggio arbitrario. Se si guarda a pyglet/sprite.py, si vedrà che questo è fatto utilizzando il modulo di matematica Python, che è per questo che è piuttosto lento. Sembrerebbe che ci sia spazio per l'ottimizzazione qui, ruotando gli sprite usando OpenGL glRotate o anche un vertex shader.

+2

Sì, questa è anche la mia conclusione. Trovo il rendering standard di pyglet/sprite troppo poco ottimizzato per qualsiasi uso pratico. Sono stato in grado di ottenere un aumento del 100% di FPS riducendo le chiamate a sprite._update_position. Vedete, viene chiamato ogni volta che viene impostata una nuova x o y o rotazione; è molto più pratico chiamarlo una volta prima del metodo draw(). –