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