Mipmapping for canvas. Ideas and comments.

Dmitry Kazakov dimula73 at gmail.com
Tue Jul 21 12:43:12 CEST 2009


Hi, all!

The tile engine has already come  over to a quite stable state by this
moment.  I  think today  i'll publish patches  for trunk.  So  now i'm
publishing my ideas about mipmapping feature of viewing mechanism.

Well, mipmapping  could be added  in two parts  of krita: the  first -
before actual merging and the second - after merging.


* The first could be done  inside KisPaintDevice class and all merging
 would be done with prescaled images.

Pros:
     + we merge only small images, not fullsized big ones
     + as a consequence, filter layers and masks are applied much
       faster

Cons:
     - too much overhead, in memory and in cpu time. Actually, a huge
       piece of work  is done for  nothing.  Parts  of image pyramids
       will never be used at all.
     - complexity of the system: alignment between layers
     - probable artefacts caused by merging after scaling


* The second  - in  KisPrescaledProjection. We merge  original images,
 then create a pyramid of a projection and scale at last.

Pros:
     + not so much overhead as we create only one pyramid for a view
     + zooming works fast thanks to the pyramid
     + no scale-merge artefacts.
     + no problems with alignment

Cons:
     - no help to filter layers


I think the  second variant is better. At least  for the beginning. So
i'm going to add it to KisPrescaledProjection. More than that, i could
try to make this image pyramid as encapsulated of the canvas subsystem
as possible,  so in fueature it could  be ported to a  paint device if
needed, or even made as a template.

As i investigated, KisPrescaledProjection have three main entry points
(input methods):

->updateCanvasProjection(rect)
->preScale()
->resizePrescaledImage(size)

These methods fit for image pyramid very well:

updateCanvasProjection()  would start a  thread that  would eventually
update pyramid

preScale() would request scaled image from pyramid.
It would look like:
QPainter gc(m_prescaledQImage);
...
m_imagePyramid.drawScaledImage(gc, ..., ..., scale);


Here is a mockup of an interface of a KisImagePyramidClass:

class KisImagePyramid {
public:
       void updateCanvasProjection(QRect rect);

       /**
        * Here are some problems with scaleX/scaleY
        * as for image pyramid they should be equal
        */
       void drawScaledImage(QPainter gc,
            QPointF topLeftScaled /* target topLeft point */,
            QRect rectUnscaled /* source rect in image */,
            qreal scale);
private:
       QVector<QImage> m_pyramid;

       KisProjectionCache /* or QImage */ m_original;
       QThreadPool m_pyramidUpdater;
};


What do you think about this idea? Maybe i've missed something?
As always, comments are welcome! =)

PS:
There are some points where i'm in doubt now:

1)  Should we  use KisProjectionCache  for storing  original  image?
I  guess not,  because  it  could  be used  much  in
drawScaledImage much.

2) Which  zoom-levels should  be stored inside  m_pyramid? I  saw that
when you  press Ctrl+'+'/'-' Krita switches across  some finite number
of levels. Which part of Krita/Koffice decides, which levels to use? I
guess, these levels and levels in m_pyramid should agree :)

3) KisPresceledProjection::Private::prescaledQImage vs
  KisPresceledProjection::Private::prescaledQPixmap?
What is the difference and where are they mostly used?


--
Dmitry Kazakov


--
Dmitry Kazakov


More information about the kimageshop mailing list