krita slow - tried with valgrind (cache)

Boudewijn Rempt boud at valdyas.org
Tue Feb 10 21:31:06 CET 2004


On Tuesday 10 February 2004 02:37, you wrote:

(Cc'd to the list, because Patrick might be able to correct me in places.)

> Very few misses - but X is not included...
> But probably it burns CPU cycles on its own.
>
> How about a test - no explicit updates. Only updates on View->Redisplay.
> Will it be able to keep up?

Nope... I tried that today, and it still cannot handle mouse movement as quick
as the Gimp. Now I know that a) the Gimp is really optimized and b) GTK/GDK
seems to have really fast routines for displaying bits of memory that happen 
to contain image data, but it should be possible to speed Krita up so it 
becomes usable. And I haven't even done the necessary code for sub-pixel 
positioning of brushes, so the lines aren't even anti-aliased. 

But I'm not nearly close to anything approaching knowledgability; all I know I 
have from http://www.levien.com/gimp/brush-arch.html and the source of the 
Gimp, which I don't understand much.

The redisplay and the painting code are already pretty well separated -- I 
don't know whether you have the Krita code handy, but what happens when 
painting is:

kis_tool_brush.cc: from mouseMoveEvent, paintLine is called, with the the 
previous mouse position and the current position (which should be as small as 
possible). paintLine calls KisPainter::paintLine. Here, we check whether the 
delta between pos1 and pos2 was big enough so we need to paint. 

If so, a rather complicated calculation I don't entirely grasp (which was 
written for a previous version of Krita) calculates the points on the line. 
This is, I think, Bresenham's algorithm. For every point, paintAt is called.

paintAt asks the current brush to create the mask, if the pressure is 
different from the previous pressure. This is done in 
KisAlphaMask::computeAlpha. This mask is combined with the current colour 
(and ultimately with gradients, patterns, color cycles, surface fields etc.) 
in KisPainter::computeDab. Here, I call alphaAt for every pixel position; 
those function calls I could conceivable skip by iterating directly over the 
QValueVector that stores the mask. That might speed things up a little.

Every pixel in the dab is set with KisPaintDevice::setPixel: from the look of 
it, this is an expensive operation, too. I think, because it calls 
KisTileMgr.writePixelData, that it loops over all pixels in the temporary dab 
for every pixel I set (Patrick, is that correct?) Creating the dab is perhaps 
the single most expensive operation because if I can cache the dab (colour 
doesn't change, pressure doesn't change), painting seems relatively smooth.

When the dab is complete, it is bitBlted onto the target layer: 
KisPainter::bitBlt, which loops over the tiles of the source (in the case of 
brushes only one tile, I guess) and matches it with the tiles of the target 
layer, calling KisPainter::tileBlt for every tile affected. And every tileBlt 
retrieves the correct colour strategy and loops over the data in the tile, 
and changes the destination. Here we could speed up things by having a LUT 
with pre-multiplied alpha values for the colours.

When the whole line is painted, I call notify; this takes some time, too, but 
not so much that if I call notify only on mouseUp, i.e., don't update the 
display during line drawing, I don't get a significantly smoother line.

I'm going to get some timing information, but my bet is on the creation of the 
dab using setPixel; the solution would be to either directly paint onto the 
target layer, keeping track of tile boundaries and so on (and I am really not 
looking forward to that), or to create a version of bitBlt that takes a 
simpler data structure than a KisPaintDevice, perhaps one that has only an 
image type and a QValueVector containing the data, perhaps just for internal 
use in KisPainter.

-- 
Boudewijn Rempt | http://www.valdyas.org/fading/index.cgi


More information about the kimageshop mailing list