Плохая производительность Pyglet

Я думаю о переносе проекта с PySFML на Pyglet. SFML — немного шаткая библиотека, и хотя она работает достаточно прилично, я решил взглянуть на Pyglet. К сожалению, Pyglet отображает неустойчивые изменения FPS при выполнении простых действий (от 20 до 800 FPS) и с трудом рисует кадры, когда я пытаюсь сделать что-то более сложное.

import pyglet

window = pyglet.window.Window()
fps_display = pyglet.clock.ClockDisplay()
labelList = []
for i in range(100):
    label = pyglet.text.Label('Hello, world',
        font_name='Times New Roman',
        font_size=36,
        x=window.width//2, y=window.height//2+i,
        anchor_x='center', anchor_y='center')
    labelList.append(label)


def main():
    pyglet.clock.schedule_interval(update, 1/30.0)
    pyglet.app.run()

def update(dt):
    for la in labelList:
        la.x += 1

@window.event
def on_draw():
    window.clear()
    for la in labelList:
        la.draw()
    fps_display.draw()


if __name__ == "__main__":
    main()

Пример глупый, но я просто беру 100 меток и перемещаю их по экрану. Это работает со скоростью около 7 кадров в секунду на моей машине. Используя SFML, отрисовывая 500 спрайтов и обрабатывая ввод, я получаю около 200 кадров в секунду.


person user3076291    schedule 05.02.2014    source источник


Ответы (3)


Рассмотрите возможность использования Batch для рисования всех ваших меток в однажды:

lbls = pyglet.graphics.Batch()
for i in range(100):
    label = pyglet.text.Label('Hello, world',
        font_name='Times New Roman', [...], batch=lbls)
labelList.append(label)
[...]
lbls.draw()

Хотя ваш пример работает с частотой кадров на несколько меньше, чем ваши целевые 30 кадров в секунду на моей машине, это улучшение позволяет ему работать со скоростью ~ 60 кадров в секунду. Попробуйте увеличить частоту вызовов update(), указанную с помощью schedule_interval(update,...), чтобы узнать, какой частоты кадров вы можете достичь.

Другое дело, что каждое присвоение члену x метки вызывает вызов ее метода _update(), который, кажется, каждый раз полностью перестраивает визуальное представление текстового содержимого метки. Таким образом, можно себе представить некоторый прирост производительности за счет наследования класса Label и перезаписи его метода _set_x() для подавления этих вызовов _update() (см. этот вопрос относительно соответствующего поведения класса Sprite).

person J. Katzwinkel    schedule 05.02.2014
comment
Спасибо за предложение, Джей. Я все еще считаю, что здесь есть более глубокие проблемы. Даже очень простая программа, которая перемещает один спрайт по экрану, не достигает 60 кадров в секунду. Pyglet явно непригоден для меня в этом состоянии. Хм... - person user3076291; 05.02.2014

Помимо использования пакетов, я получил заметный прирост производительности (на некоторых машинах), отключив debug_gl сразу после импорта pyglet:

import pyglet
pyglet.options['debug_gl'] = False
person Sebastian    schedule 10.02.2014

Реструктуризация кода как класса помогла повысить производительность моего компьютера. Даже без вызова пакетной графики он может нарисовать 100 этикеток. Я не уверен, почему это улучшает производительность (просто удаляет декоратор).

import pyglet

class GameWindow(pyglet.window.Window):
    def __init__(self, *args, **kwargs):
        super(GameWindow, self).__init__(*args, **kwargs)
        pyglet.clock.schedule_interval(self.update, 1.0/60.0)
        self.labelList = []
        self.fps_display = pyglet.clock.ClockDisplay()
        self.labelBatch = pyglet.graphics.Batch()
        for i in range(1000):
            label = pyglet.text.Label('Hello, world',
            font_name='Times New Roman',
            font_size=36,
            x=self.width//2, y=self.height//2+i,
            anchor_x='center', anchor_y='center',
            batch = self.labelBatch)
            self.labelList.append(label)

    def update(self, dt):
        for la in self.labelList:
            la.x += 1

    def on_draw(self):
        self.clear()
        self.labelBatch.draw()
        self.fps_display.draw()

if __name__ == "__main__":
    game = GameWindow(width=800, height=600)
    pyglet.app.run()
person CodeSurgeon    schedule 10.02.2014