GNOME Bugzilla – Bug 314790
Last modified: 2012-01-31 23:22:21 UTC
This afternoon I played a bit with cairo and tried to port gnometris to it. I'm
attaching a patch with the start of some cairoification of gnometris. let's make
it clear right away: the patch is far from complete... in fact it's mostly
completetely wrong and needs redoing from scratch.
The reasons I am attaching it here are:
- I played with the same thing a couple of weeks ago and obviously I wiped it
away from my hard disk by mistake
- this started as a quick hack to try cairo and I don't know if I'll have time
to look at it in the forseable future, so someone else may find it useful as a
starting point... or as an example on how not to do it :)
- I need some advices on how things should be done and since I never have the
chance to catch Callum on irc I'll post my doubts here.
- I'll try to summarise some of the problems and implementation ideas so that
someone else (or even me in the future) doesn't have to find them out from
[so to make it short, feel free to close this if it gets in your way, it's just
an excuse to write down some notes :) ]
- gnometris currently uses gnome-canvas, which is able to hold the state and
redraw itself. Thus, currently code is split in two classes blockops (holds the
state of the field and handle operations on blocks) and field (which does the
drawing). However when moving away from canvas the following problem arises:
Blockops needs Field to draw the changes, but in turn field needs blockops to
know the current state of the field when redrawing itself. This means that major
refactoring is needed: either the two classes are merged into one or the classes
are made one the specializtion of the other (e.g. Field and FieldDrawer
inheriting from field and drawing with cairo) or something else. Suggestion on
the preferred way to follow are welcome.
- We must decide if continue to draw blocks from bitmaps or go completely vectorial
- drawing moving blocks with cairo as I did leaves around garbage due to AA, I
have no clue on how to fix that
- the drawing model I went with its probably slow as hell, but I need someone
with more experience to suggest a better way. Currently it works like this: we
have three cairo_surfaces: buffer, background and foreground. Background holds
the background color/image and its cached so that it's redrawn only when the
drawing area size changes. Foreground is where the blocks are drawed on. Buffer
is the backing buffer: when drawing, the relevant part of background is painted
on buffer, then foreground is painted on top and if needed the "Pause" and
"GameOver" messages are painted on it too. When expose is received the relevant
part of buffer is blitted on the drawing area. [drawing on the buffer currently
repaints it all, but this is easy to improve]
pieces of code probably worth saving: it's probably worth saving how the "pause"
and "gameover" messages are drawn since calculating the size is not totally trivial.
Created attachment 51522 [details] [review]
bits and pieces of cairoification
I have also been experimenting with Cairo stuff using Ataxx. Its a very nice
library for drawing but performance is a definite issue.
To response to some of your points:
The class hierarchy in gnometris is shagged. The fact that most of the code is
in one class (Tetris) is a good indication of that. There should be one object
with a canonical view of the field and that provides the data to the drawing
code. I can think of several ways to do it, any of them are better than what's
On the drawing artifacts issue: you can't do things with Cairo the way you can
with pixmaps. It seems that the best way to do things is a complete redraw each
time (unless you are certain there is no overlap between bits of the drawing).
The performance implications of this aren't as bad as you might expect - at
least with Ataxx where the things that change are the most complex.
Speed: Cairo is blindingly fast for lines, polygons and similar things with
solid-color fills. It is terrible when using pixmaps for fills and when using
radial gradients. Your three-buffer method is a sane way to do things, but won't
fix some of the underlying problems.
Vector vs. bitmaps. Cairo is well set-up for vector stuff, but doesn't handle
images well. Wonderful things could be done with vector-based drawing code, but
at the expense of easy-to-make themes. I'm still not sure what the best way to
go is, although I am seriously considering moving the Ataxx drawing engine back
to being non-cairo just because of performance issues.
can you elaborate on what you mean with "canonical view of the field"?
The way I'd like to see it done is split in three objects (MVC), the field
holding the state of the board, the view implementing the drawing and the
controller implementing the blockops operations... anyway this would be pretty
much a rewrite for little gain, so I don't plan to try it any time soon :)
In the slightly updated patch below I choose the way which required less
changes: I made Field inherit from Blockops so that it has access to the field
state, the subclass overrides redraw() from the base class and implements it
throgh cairo [redraw() should probably be marked virtual, I need to check my C++].
Apart from that, what the patch does is simply go on and redraw the whole thing
every time (the foreground surface is not needed anymore) and also fixups some
minor things so that the patch is now playable for testing (the blocks are just
The sad result is that the game is very unresponsive :(
However from a bunch of timers sprinkled there the time doesn't seem to be spent
in drawing... ideas?
 I know I said I wasn't going to touch it soon, but I had half an hour to
kill and I did just read your comment about redrawing the whole field maybe
being acceptable so I went on and tried it.
Created attachment 51590 [details] [review]
update (still just a test)
by the way, maybe the cairoification of the preview widget (actually just the
background and the lines, not the block itself) should be split out and applied
since it doesn't seem a performance problem and makes the disabled preview
slightly less ugly.
"Canonical" was a very bad choice of words given that I didn't explain the model
I was thinking of. I was taking MVC as a given, but was thinking of several
objects acting together to get the model - hence the idea of one canonical
object for the view to treat as the model. The details are really irrelevant
since I'm not sure what was going through my head that night was a good idea.
On the timing issue: you have to be very careful measuring Cairo stuff. It
caches the drawing operations and then does the actual rendering in one block
once it knows what it has to draw with. I'm not sure of the exact details, but
measuring the time spent in small groups of Cairo calls can be *very*
misleading. I tend to measure functional blocks (e.g. background, pieces and
grid for Ataxx) and an overall time. I have frequently seen vast improvements in
one block only to find the time has just moved to a later block.
I have not yet found an efficient way to handle images/pixbufs in Cairo. This is
probably where your speed problem lies. I suspect that anything which involves
the large tranformation matrices needed by the interpolation routines causes
trouble. I haven't tried turning down the interpolation quality (I tried a
non-image based approach instead) but I expect that will help. Note that I
haven't asked for advice on this yet either, so it may not be real problem.
Created attachment 51609 [details] [review]
I'm such an idiot sometimes... while at lunch it occurred to me that it wasn't
a real performance problem but it was just me forgetting to redraw each time a
key was pressed :/
With this version the game seems to playable without problems on my system even
when using a bacground image.
The blocks are still just semitransparent red rectangles because I have no clue
from an artistic point of view on how to draw something nicer.
Personally I feel that we should experiment with completely vectorial blocks
since they can become very nice (e.g translucent etc), but that doesn't exclude
the possibility of having pixamepped alternative thems: my idea was just the
recache the blocks pango_surfaces on configure and use them as sources to draw;
such surfaces can either be completely hand drawn or got from a loaded pixmap.
Screenie attached below
Created attachment 51610 [details]
I posted a handful of svg block themes to #300503 . FWIW, librsvg's cairo work
might be ready in time for release with GNOME 2.14, but at this stage it's too
early to know for certain.
I'd probably suggest a fork of graphics stuff to work with it until we know for
certain that Caleb, Dom, and Carl will pull it off, but I've been on a bit of a
GNOME hiatus, and will be for at least another month.
Since this seems to have been sitting here for a while, I have applied Paolo's
patch and started playing with it. I have the foreground drawing going to the
point where it looks OK, but it doesn't use external theme files and is a bit
slower. I will probably commit what I have tonight since it is at least playable.
Hey Callum, it's great to see that you have picked things up where I left! I
really had no time to work on this and I was also waiting for the ability to
draw cairo paths from svg to appear.
I also had some pending stuff in my tree that I didn't attach here, but I have
not been touching it for such a long time that I really don't recall what it
did, oh well probably you fixed that up already. One changeset that it's easy to
extract, but not very important was moving the Block and SlotType structs from
tetris.h to blockops.h.
The preview still uses the old graphics (well, you probably know this) and has
an ugly yellow border: that was just me trying to draw my first cairo recangle
and can surely go away.
Minor nitpick - feel free to tell me to fsck off, you are the one who maintains
it - any chance you could use the same coding style as the surrounding code
when adding functions?
We should be able to use librsvg with the cairo backend sometime during this
cycle, but since we won't have the ability to carve up the theme with subpixbuf,
they plan to add API to grab graphics out of a single SVG by passing in an xlink
handle like "king_of_hearts" or "gnometris_block_one". I'll probably patch it up
by the time it's ready.
Paolo: I figured that if you had anything else significant you would have posted
it and since I was "in the mood" even if I did duplicate your work I would enjoy
From here, I want to abstract parts of the drawing code so that "theme engines"
can be used. One would obviously imitate the traditional pixmap scheme, but I
have a couple of other ideas that can't be done that way.
Once I have something approximating themes running again I'll close this bug
since all regressions I know of will then be fixed.
Callum: cool, as I said I am really happy you picked this up, my pending changes
were just small stuff and anyway I totally forgot what exactly they were.
I tried cvs out and it's really nice, just some small observations:
- with the default black backround the blocks look weird since you cannot see
the think border
- when there is just a 1x1 'hole' it's really hard to distinguish it from a block
- when you start having many blocks on the field, moving laterally becomes
Keep up the good work!
The drawing style is definitely not final - it is meant to be something that is
representative of a reasonable drawing-load for cairo. Having said that, I'd
forgotten about testing against the default background - I'm using a pixmap to
give the code the worst-case for speed (although background detail is only an
issue at resizing time).
I know about the speed issues, on my machine there is no slowdown, but the CPU
activity indicates that it is borderline. I hope to get it only drawing changes
in the near future. For Ataxx that made a vast difference in responsiveness.
Right, the code in CVS is now in a tolerable state and has no feature
regressions. So I am closing the bug.
One note: themes are now code rather than images. In principle a theme could be
written that could read images off disk, but that hasn't been written yet and
probably won't be until the cairo back-end to librsvg is stable.
Also, the existing themes are not very pretty. The default "plain" theme is OK
and reasonably fast, but the "joined" theme is currently just a demo of what you
can do if you aren't restricted to a set of square bitmaps. See the file
renderer.cpp for details (themes are C++ classes so that you can change only the
bits you want to when writing a new theme).
This bug is being reassigned to the "quadrapassel" component so we can close the gnometris bugzilla component. Apologies for the mass email!