Hi all!

I'm currently working on a game made with Qt and I'm struggling with performance issues in the rendering of the game scene, hence this little question. I've browsed those forums a bit and haven't been able to find a solution to my problem, so here it goes!


Context
The map of our game is a cylinder: exiting on the "right" of the map brings you back at the "left" transparently. The map must therefore be scrollable without the user noticing when the "shift" occurs.

The map features many background elements like regions, rivers, sea... and also foreground features (player tokens).


Implementation
To implement the aforementioned features, I used QGraphicsScene and QGraphicsView. All the elements in the game (such as rivers for instance) are represented by three distinct QGraphicsItems, grouped in a subclass of QGraphicsItemGroup (that reimplements "paint" with an empty method to be totally invisible): the world is therefore represented thrice. When users scroll the map (using shortcuts; scrollbars are hidden), the view automatically translates itself to always be centered on the central view. See image below to have an illustration of what I'm talking about.

map.png
(over 9000 hours in MSPAINT!)

We currently have up to a few thousands of QPolygonItem on the map, and a few dozens QPixmapItems on top of them. We use OpenGL rendering (with QGLWidget).


Issue
The issue that we have here is that rendering of the scene is slow. By using a naive call to "clock" I've gathered stats about QGraphicsView::paintEvent. It currently takes around 50ms to render a small test scene on my (powerful) dev machine. This is far too much, as we want to let the user scroll the map smoothly (so we aim at keeping that time below 30ms as much as possible). Callgrind shows that 90% percent of that time is spent in QGraphicsPolygonItem::paint.

The issue here is that as far as I know, with OpenGL rendering the ViewPortUpdateMode option is ignored: scrolling the map means a full rendering at each step. Scaling is even worse (but that might be linked to the fact some items have "cosmetic" (scale-independent size) lines; many things might need to be recomputed).


Tested solutions
Before coming here to ask about this issue, I tried or thought about several solutions, none of which proved to boost the performance of the rendering.

One big item versus many small ones.
Rivers being totally static (not clickable nor interactive in any way), I've tried to use one big subclassed QGraphicsItem to paint them all. That way, in the paint method, I had only one Painter::save, one Painter::restore and one Painter::setBrush for all the rivers, instead of having hundreds of scattered QGraphicsPolygonItems. Rendering time doubled. Idea scrapped.
I suppose it's because Qt is able to sort between displayed items and not displayed items and draw only what's useful (if it's indeed the reason, that's a shame that QGLWidget do not support partial updates; that'd solve our problem here, I guess).

Caching the map in a pixmap.
This seems like a interesting idea, since we have a lot of static elements in the background. Also, as the map is modified only once in a while but scrolled far more often, caching the result seems like a perfect idea.
The problem with that solution is that we have lots of cosmetic items, as mentioned before. This would make each zoom change a bit slow. The other problem is that we have huge variations of zoom levels, and that rendering the whole map at the maximum scale is impossible (unless there's a way to easily cache, crop and draw >2Go bitmaps I haven't heard of ^^).
I've also been unable to paint directly on a QQraphicsView: attempts to create a QPainter in the paintEvent method all failed with a "Widget painting can only begin as a result of a paintEvent" error. And I can't see any other way to circumvent items drawing if I cache the scene with a custom call to QGraphicsView::render.

Not using transparency.
Most of my items use alpha blending; it's nicer that way. :)
I've tried to disable transparency by ensuring all alpha values were set to 1. This didn't change anything, which surprised me. I suppose there is a way to totally deactivate transparency (which prevent Qt from doing the calculations at all), but I haven't been able to find anything relevant yet.

Not having three items for each element
That might seem obvious, as it would cut by a solid three the rendering time. But this is not as easy as it might seem. One of the problems is that most elements are interactive. I can click on them and act with them (also they're raised when clicked). As the picture above shows, I might interact without knowing it with items that are not on the "main map" but on one of the duplicates on the sides. As most of the interaction is custom-made (my custom mousePressEvent method uses "itemsAt" to know what item was clicked), I suppose I COULD wrap all interactions to shift user input, but then how would I manage to draw everything thrice?


Questions
So I'm left with this issue: I can't find a way to cache the map; I can't seem to find a way to draw each item only once and then "copy / paste" the rendered result; I can't find a way to simulate partial rendering.

So, a few questions: are there rendering tweaks I might haven't heard of? Is there a way to speed up polygons rendering, maybe by caching calculations as OpenGL call lists would? Is the use of QGraphicsItemGroup for scattered items a problem as far as cropping go? Is there a way to simulate partial rendering with QGLWidget?

Thank you if you made it that far. ^^
I'm open to all suggestions or leads; thank you in advance for your time.