Yes, I've run into that problem too. My two cents on still using PyGame:
My solution is to make an OpenGL character set out of PyGame as a texture atlas. The text to be rendered can then just be converted to a list of indices into the texture atlas and the individual characters drawn on individual quads using the proper subimage. I've used this technique for framerate counters in several (unreleased) games (situations where the text changes continuously).
If for some reason even that is too slow (because of the extra geometry; I can only imagine this being an issue if you're trying to render thousands of characters at a time), you can cram those quads into a display list or VBO and cache the result for arbitrary use. A VBO will also let you update individual sections of the geometry, so you can still change section(s) of the cached text to whatever you want at the computational cost of updating only
the changes. A more advanced technique would be to create words just by compositing character textures via glCopyTex______ functions. That will give you a single texture (a "word" texture atlas, if you will) that you can cache and draw on a single quad as you please.
Of course, if the result of the font rendering is cached, the result only need be generated once--and there will be no drop in framerate, no matter how it was generated in the first place (direct rendering, texture atlas, glCopyWhatever() compositing, etc.). I've used this in conjunction with direct rendering for several games (ex: the now somewhat old Spacewar Multi
, whose code may help you) where I was too lazy to set up a proper character set (texture atlas).