[cairo] clipmask of multiple rects in different angles

Enrico Weigelt, metux IT consult enrico.weigelt at gr13.net
Wed Jul 20 23:22:39 UTC 2016

On 20.07.2016 23:46, Theo Veenker wrote:

>> Maybe the damage tracking itself is slowing it down ... I'll now try
>> to cache the matrices.

Just implemented it - doesn't seem to have much effect.

And still, on drm it's much slower than on xcb. The funny part here:
it's not even deterministic - sometimes mouse movements (which in turn
trigger two widgets to be repainted in my test program, as they show
the positions and currently hover'ed widget) lags behind about 0.5..1s,
but sometimes it's way faster - no idea what could cause that big

> Are you also saving the bounding boxes of your graphic objects? 

Just the rect (coordinates and angle) relative to the parent, but not
the absolute positions.


I'm also caching the widget contents (including their subs's) as an
cairo_pattern_t, rendered within an group. They get re-rendered when
the widget gets a dirty flag - in that case the whole parent line also
needs to be re-rendered.

Haven't measured yet what's really eating up most of the time, whether
it's the recursive rendering (within a group) or actual drawing onto
screen. I'd suspect the latter, as xcb is magnitudes faster than xcb.

By the way: when exactly is the clipping applied (and clipped-out stuff
dropped out) ? Is that device specific or generic ?

> I suppose it is not efficient if you need recalculate the bbox (by drawing
> onto a dummy surface) before each redraw.

Actually, I'm not recalculating it by drawing. The (relative) rects
and the matrices are stored within the widgets. For damage tracking,
rect and matrix are passed upwards and transformed with the parent

As I'm not using angles != 0 right now, I maybe could add a bypass that
just adds positions w/o using matrices.

> What also helps *a lot* is drawing only once every vertical retrace. 

hmm, in general, I'm always redrawing if an event caused the screen to
become dirty (passed up the handler hierarchy as an result code flag)
and on xcb when the server requests it.

In any case, when a widget is dirty, it's parent is also marked dirty,
so finally the root is always repainted when something changes. But in
parallel the affected (absolute) rects are recorded and used as clip
when the root's pattern is drawn onto screen.

Theoretically, the clip should limit the actual draw operations on the
underlying framebuffer to the dirty regions.

> In my setup all graphic objects have a current and a new state (this means
> every attribute such as x or y, color etc. is doubled). Let's say we're
> not using a back-buffer then a graphics expose will cause a redraw using
> the current state of the objects. And only at vertical retrace the
> drawing is updated to refrect the new state. In this aproach you can
> change the state of objects as often as you want with nearly zero CPU
> load. Only at retrace when changes are drawn you will have load. So if
> you're the only process drawing you'll have almost a full video frame to
> do the job; that should be plenty of time.

hmm, how could an actual implementation look like ?

Have a different thread sleeping on some lock, which is released as soon
as there's something to repaint and then sleep until vsync event occours
(sync read() on drm fd ...) ?

> Personally I don't use the cairo region type. I just create my own array
> of integer rectangles (do floor on x, and y; ceil on w and h) from which
> the clip mask is then created.

Does your implementation also allow arbitrary angles ?
For now, my test program doesn't use angles yet, but I wanna support it
in the future. I'm also planning to support widget zooming (in that way
that the widget class itself doesn't have to care about it - everything
handled by the engine).


More information about the cairo mailing list