pyglet.graphics: IndexError при создании массива ctypes - PullRequest
3 голосов
/ 28 февраля 2012

Я разрабатываю небольшую игру с pyglet. Одна из центральных частей, конечно же, рисование цветных прямоугольников. Первоначально я делал это, создавая изображения в памяти и blit() используя их, что работало нормально. Заметив, насколько уродливым, обходным и неэффективным (да, я профилировал - ColorRect.draw() заняло значительное время и стал в 10 раз более эффективен благодаря этому изменению), я начал создавать списки вершин вместо этого с помощью pyglet.graphics.Batch (я скопировал большую часть дословно код из одного из примеров). С тех пор я столкнулся со странным исключением в каком-то низкоуровневом коде OpenGL, для которого мне не удалось найти причину или надежно воспроизвести.

Нет явного отношения к игровым событиям - как, впрочем, ничего особенного не происходит прямо перед этим, или я постоянно скучаю по нему. Поскольку ошибка происходит где-то глубоко в цикле событий, я не могу легко отследить, какое обновление позиции вызывает ее. Честно говоря, я в тупике. Таким образом, я расскажу о том, что узнал, и надеюсь на какого-нибудь экстрасенса.

Я опробовал его на 32-битной Windows 7 (я скоро смогу попробовать его на Ubuntu 11.10) с Python 3.2.2, с редакцией pyglet 043180b64260 (взятой из кода Goggle и созданной из исходного кода, 1.1 .4 релиз сложнее установить, так как он не запускает 2to3 автоматически, хотя кажется, что он одинаково готов к py3k). Я, вероятно, обновлю до последней версии Mercurial, но это всего лишь несколько коммитов, и изменения кажутся совершенно не связанными.

Полный возвратный путь (некоторые пути были подвергнуты цензуре из принципа, но обратите внимание, что он в своем собственном virtualenv):

Traceback (most recent call last):
  File "<my main file>", line 152, in <module>
    main()
  File "<my main file>", line 148, in main
    run()
  File "<my main file>", line 125, in run
    pyglet.app.run()
  File "<virtualenv>\Lib\site-packages\pyglet\app\__init__.py", line 123, in run
    event_loop.run()
  File "<virtualenv>\Lib\site-packages\pyglet\app\base.py", line 135, in run
    self._run_estimated()
  File "<virtualenv>\Lib\site-packages\pyglet\app\base.py", line 164, in _run_estimated
    timeout = self.idle()
  File "<virtualenv>\Lib\site-packages\pyglet\app\base.py", line 278, in idle
    window.switch_to()
  File "<virtualenv>\Lib\site-packages\pyglet\window\win32\__init__.py", line 305, in switch_to
    self.context.set_current()
  File "<virtualenv>\Lib\site-packages\pyglet\gl\win32.py", line 213, in set_current
    super(Win32Context, self).set_current()
  File "<virtualenv>\Lib\site-packages\pyglet\gl\base.py", line 320, in set_current
    buffers = (gl.GLuint * len(buffers))(*buffers)
IndexError: invalid index

Работа с посмертным кодом (активный пошаговый просмотр кода до тех пор, пока он не оказался невозможным, поскольку FPS снизился с 60 до 7) pdb показывает:

  • buffers - список целых чисел; Я понятия не имею, что они представляют или откуда они берутся, но они взяты из списка с именем self.object_space._doomed_textures (где self - объект окна). Связанный комментарий говорит, что этот блок кода выпускает текстуру, запланированную для удаления. Я не думаю, что я явно использую текстуры где-либо, но кто знает, что делает pyglet под капотом. Я предполагаю, что эти целые числа - это идентификаторы или что-то из текстур, подлежащих уничтожению.
  • gl.GLuint - псевдоним для ctypes.c_ulong; Таким образом, (gl.GLuint * len(buffers))(*buffers) создает массив ulong такой же длины и содержания
  • Я могу оценить то же самое выражение в приглашении pdb без ошибок или повреждения данных.

Независимые эксперименты (за пределами virtualenv и без импорта pyglet) с ctypes показывают, что IndexError вызывается, если конструктору массива передано слишком много аргументов. Это не имеет смысла, и эксперименты, и логика предполагают, что длина и количество аргументов всегда должны совпадать.

  1. Есть ли другие случаи, когда это исключение может произойти? Может ли это быть ошибкой pyglet, или я неправильно использовал библиотеку и пропустил соответствующее предупреждение?
  2. Может ли код, который создает и поддерживает списки вершин, быть полезным для отладки этого? Там, наверное, что-то с этим не так. Я уже смотрел на это, но так как у меня мало опыта с pyglet.graphics, это было ограниченное использование. Просто оставьте комментарий, если хотите увидеть код ColorRect.
  3. Есть еще идеи, что может вызвать это?

1 Ответ

0 голосов
/ 08 марта 2012

Довольно сложно дать действительно актуальный ответ, так как код не указан, но из того, что я вижу по выводу ошибки.

buffers = (gl.GLuint * len(buffers))(*buffers)

Так что, если я правильно понимаю, вы умножаетеразмер GLuint (4 байта) с вашей фактической длиной буфера (если инициализирован).Может быть, поэтому ваш индекс недействителен, потому что он слишком высокий?

Обычно это было бы нормально, поскольку буфер в байтах, но вы сказали, что это список целых чисел?

Надеюсьэто помогает

...