Threading in Krita

We're in a mess, right now. One of the goals of Krita 2.0 was to 
use threading to make sure we make optimal use of multicode processors
and keep the user interface responsive. Here's an analysis of where we
are: next up, a design for 2.1.


--- 1.6 ---

In Krita 1.6, we used threading in the following places:

 * in the resource server, for loading resources like brushes
 * in the filters gallery, for preparing the thumbnails
 * in the scale visitor, only we called KisScaleWorker::run, not
start, so it never got threaded


--- 2.0 ---


---- threadweaver ----


In Krita 2.0, threading is generally based on ThreadWeaver. We use or
used ThreadWeaver directly in:

 * KisProjection: when we still used the top-down recomposition
strategy, KisProjection used ThreadWeaver to tile the areas that were
to be recomposited. This failed because every layer needed to keep
track of dirty areas, and there was no way to make this threadsafe,
not even using QRegion. However, I have patch that re-enables threaded
recomposition, but this breaks on what looks like a bug in ThreadWeaver.

 * KisThreadedApplicator: this takes a paint device and (optionally)
divides it into areas and applies a KisJob to it. Only filters
currently use this. Right now, a job in KisThreadedApplicator cannot
be cancelled, and the way filters use it isn't safe, because
KisFilterHandler can be entered before the theaded applicator is done.
Because of a clash with KoUpdater, we need to disable this for all
filters for 2.0 :-(.
 
 * Colorspace conversion: there is a ConversionJob that could be used
to multi-thread the conversion of a single run of pixels from one
colorspace to another. This isn't used at all, and should probably be
converted to use KisThreadedApplicator anyway. I've svn rm'ed it now.

 * We used to use ThreadWeaver to recompute the thumbnails in the
filters gallery, however that got replaced by lazy creation of
thumbnails in KisFiltersModel. (At least, I hope it's lazy!)
Note that we still need threading here: since when you expand a catetory in the tree view, 
then Qt will ask for all the previews (mostly because it needs to know the 
size of all elements), so we would need threading there too, for the 
categories with a lot of filters


---- KoAction ----


There is also KoAction. KoAction is a ThreadWeaver-based class that
executes a certain bit of code in a thread in threadweaver. It can
take care of progress updates, gui updates but not cancelling of
long-running actions.

We have wrapped KoAction in KisNodeAction, which locks the node (with
setSystemLocked) before starting the action. KisNodeAction isn't used
anywhere, and I have svn rm'd it.

We did not use KoAction anywhere else, except indirectly through
KoProgressUpdater.


---- KoProgressUpdater ---


KoProgressUpdater is only used in Krita (extensively, to report
progress of tasks with subtasks, like tiled filters) and in
KoPrintingDialog. The goal of KoProgressUpdater is to make it safe to
update one progress bar widget from multiple non-gui threads. Using
KoProgressUpdater does not make your task execute in a thread:
whenever you increase the progress, a KoAction is executed (well,
scheduled, the KoAction api is a bit confusing here) that, when
ThreadWeaver executes the scheduled action assembles the total
progress from all subtasks and updates the widget. 

(I think this whole class is horribly over-designed -- so
over-designed that I when I started using it didn't see that it was
over-designed. All that is needed is an object that knows the list of
subtasks and their relative weight, a signal sent from worker threads
that updates the progress, a signal from that object to the worker
threads that informs them of a cancel request and a signal to the
progress reporting thingy. The signals will be sent with a
Qt::QueuedConnection, and everything is as safe as houses -- maybe
that didn't exist when KoProgressUpdater was created).


---- QThread(Pool) ----


We use QThread and QThreadPool directly in the following cases:

 * deferred painting. The Freehand tool queues paint actions and
executes them in a QThread.

 * resource loading (like patterns, paintop presets and brushes)

 * swapping out of tiles (but only in the new tiles backend, which
isn't enabled by default because filters crash with it)
 
 * tile compressor: this compressed old tiles, like undo information.
It isn't enabled by default.

 * histogram calculation in the histogram docker.

