The Raspberry Pi aims to be a low-cost educational tool that anyone can use to learn about electronics and programming. Python and pygame are included in the Pi's programming toolkit. And since last year, thanks in part to sponsorship from the Raspberry Pi Foundation, PyPy also works on the Pi (read more here).
With PyPy working on the Pi, game logic written in Python stands to gain an awesome performance boost. However, the original pygame is a Python C extension. This means it performs poorly on PyPy and negates any speedup in the Python parts of the game code.
One solution to making pygame games run faster on PyPy, and eventually on the Raspberry Pi, comes in the form of pygame_cffi. pygame_cffi uses CFFI to wrap the underlying SDL library instead of a C extension. A few months ago, the Raspberry Pi Foundation sponsored a Cape Town Python User Group hackathon to build a proof-of-concept pygame using CFFI. This hackathon was a success and it produced an early working version of pygame_cffi.
So for the last 5 weeks Raspberry Pi has been funding work on pygame_cffi. The goal was a complete implementation of the core modules. We also wanted benchmarks to illuminate performance differences between pygame_cffi on PyPy and pygame on CPython. We are happy to report that those goals were met. So without further ado, here's a rundown of what works.
- Surfaces support all the usual flags for SDL and OpenGL rendering (more about OpenGL below).
- The graphics-related modules color, display, font and image, and parts of draw and transform are mostly complete.
- Events! No fastevent module yet, though.
- Mouse and keyboard functionality, as provided by the mouse and key modules, is complete.
- Sound functionality, as provided by the mixer and music modules, is complete.
- Miscellaneous modules, cursors, rect, sprite and time are also complete.
With the above-mentioned functionality in place we could get 10+ of the pygame examples to work, and a number of PyWeek games. At the time of writing, if a game doesn't work it is most likely due to an unimplemented transform or draw function. That will be remedied soon.
In terms of performance, pygame_cffi on PyPy is showing a lot of promise. It beats pygame on CPython by a significant margin in our events processing and collision detection benchmarks, while blit and fill benchmarks perform similarly. The pygame examples we checked also perform better.
However, there is still work to be done to identify and eliminate bottlenecks. On the Raspberry Pi performance is markedly worse compared to pygame (barring collision detection). The PyWeek games we tested also performed slightly worse. Fortunately there is room for improvement in various places.Invention & Mutable Mamba (x86)
Here's a summary of some of the benchmarks. Relative speed refers to the frame rate obtained in pygame_cffi on PyPy relative to pygame on CPython.
|Benchmark||Relative speed (pypy speedup)|
|N2 collision detection on 100 sprites (x86)||4.14|
|N2 collision detection on 100 sprites (Pi)||1.01|
|Blit 100 surfaces (x86)||1.06|
|Blit 100 surfaces (Pi)||0.60|
|Mutable Mamba (x86)||0.72|
|stars example (x86)||1.95|
|stars example (Pi)||0.84|
Some not-so-great news is that PyOpenGL performs poorly on PyPy since PyOpenGL uses ctypes. This translates into a nasty reduction in frame rate for games that use OpenGL surfaces. It might be worthwhile creating a CFFI-powered version of PyOpenGL as well.
Where to now?
Work on pygame_cffi is ongoing. Here are some things that are in the pipeline:
- Get pygame_cffi on PyPy to a place where it is consistently faster than pygame on CPython.
- Implement the remaining modules and functions, starting with draw and transform.
- Improve test coverage.
- Reduce the time it takes for CFFI to parse the cdef. This makes the initial pygame import slow.
If you want to contribute you can find pygame_cffi on Github. Feel free to find us on #pypy on freenode or post issues on github.