Commit b0797472 authored by Cyrille Berger's avatar Cyrille Berger

introduce a global cache for color conversion transformation (it's internal to...

introduce a global cache for color conversion transformation (it's internal to KoColorSpace but shared between instance), it replaced the old code that was specific to one instance, and didn't work when a color space is destroyed. On a side note, the new cache take into account the rendering intent.

The bug fix can't easily be applied to the stable branch, so next stable release won't include, but it's going to be in next major release.
BUG:151345

svn path=/trunk/koffice/; revision=743410
parent b9772413
......@@ -37,6 +37,7 @@ set(pigmentcms_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/KoFallBackColorTransformation.cpp
${CMAKE_CURRENT_SOURCE_DIR}/KoHistogramProducer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/KoLcmsColorSpace.cpp
${CMAKE_CURRENT_SOURCE_DIR}/KoColorConversionCache.cpp
${CMAKE_CURRENT_SOURCE_DIR}/colorprofiles/KoIccColorProfile.cpp
${CMAKE_CURRENT_SOURCE_DIR}/colorprofiles/KoHdrColorProfile.cpp
${CMAKE_CURRENT_SOURCE_DIR}/colorprofiles/KoLcmsColorProfileContainer.cpp
......
/*
* Copyright (C) 2007 Cyrille Berger <cberger@cberger.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "KoColorConversionCache.h"
#include <QHash>
#include <QList>
#include <KoColorSpace.h>
struct KoColorConversionCacheKey {
KoColorConversionCacheKey(const KoColorSpace* _src, const KoColorSpace* _dst, KoColorConversionTransformation::Intent _renderingIntent) : src(_src), dst(_dst), renderingIntent(_renderingIntent)
{
}
const KoColorSpace* src;
const KoColorSpace* dst;
KoColorConversionTransformation::Intent renderingIntent;
bool operator==(const KoColorConversionCacheKey& rhs) const
{
return (*src == *(rhs.src)) and (*dst == *(rhs.dst)) and (renderingIntent == rhs.renderingIntent);
}
};
uint qHash(const KoColorConversionCacheKey& key)
{
return qHash(key.src) + qHash(key.dst) + qHash(key.renderingIntent);
}
struct KoColorConversionCache::CachedTransformation {
CachedTransformation(KoColorConversionTransformation* _transfo) : transfo(_transfo), use(0)
{}
~CachedTransformation()
{
delete transfo;
}
bool available() {
return use == 0;
}
KoColorConversionTransformation* transfo;
int use;
};
struct KoColorConversionCache::Private {
QMultiHash< KoColorConversionCacheKey, CachedTransformation*> cache;
};
KoColorConversionCache::KoColorConversionCache() : d(new Private)
{
}
KoColorConversionCache::~KoColorConversionCache()
{
foreach(CachedTransformation* transfo, d->cache)
{
delete transfo;
}
delete d;
}
KoCachedColorConversionTransformation KoColorConversionCache::cachedConverter(const KoColorSpace* src, const KoColorSpace* dst, KoColorConversionTransformation::Intent _renderingIntent)
{
KoColorConversionCacheKey key(src, dst, _renderingIntent);
QList< CachedTransformation* > cachedTransfos = d->cache.values( key );
if(cachedTransfos.size() != 0)
{
foreach( CachedTransformation* ct, cachedTransfos)
{
if(ct->available())
{
ct->transfo->setSrcColorSpace(src);
ct->transfo->setDstColorSpace(dst);
return KoCachedColorConversionTransformation(this, ct);
}
}
}
KoColorConversionTransformation* transfo = src->createColorConverter( dst, _renderingIntent);
CachedTransformation* ct = new CachedTransformation(transfo);
d->cache.insert(key, ct);
return KoCachedColorConversionTransformation(this, ct);
}
void KoColorConversionCache::colorSpaceIsDestroyed(const KoColorSpace* cs)
{
QMultiHash< KoColorConversionCacheKey, CachedTransformation*>::iterator endIt = d->cache.end();
for( QMultiHash< KoColorConversionCacheKey, CachedTransformation*>::iterator it = d->cache.begin(); it != endIt; )
{
if(it.key().src == cs or it.key().dst == cs)
{
Q_ASSERT(it.value()->available()); // That's terribely evil, if that assert fails, that means that someone is using a color transformation with a color space which is currently being deleted
delete it.value();
it = d->cache.erase( it);
} else {
++it;
}
}
}
//--------- KoCachedColorConversionTransformation ----------//
struct KoCachedColorConversionTransformation::Private
{
KoColorConversionCache* cache;
KoColorConversionCache::CachedTransformation* transfo;
};
KoCachedColorConversionTransformation::KoCachedColorConversionTransformation(KoColorConversionCache* cache, KoColorConversionCache::CachedTransformation* transfo) : d(new Private)
{
Q_ASSERT(transfo->available());
d->cache = cache;
d->transfo = transfo;
d->transfo->use++;
}
KoCachedColorConversionTransformation::KoCachedColorConversionTransformation(const KoCachedColorConversionTransformation& rhs) : d(new Private(*rhs.d))
{
d->transfo->use++;
}
KoCachedColorConversionTransformation::~KoCachedColorConversionTransformation()
{
d->transfo->use--;
Q_ASSERT(d->transfo->use >= 0);
delete d;
}
const KoColorConversionTransformation* KoCachedColorConversionTransformation::transformation() const
{
return d->transfo->transfo;
}
/*
* Copyright (C) 2007 Cyrille Berger <cberger@cberger.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _KO_COLOR_CONVERSION_CACHE_HPP_
#define _KO_COLOR_CONVERSION_CACHE_HPP_
class KoCachedColorConversionTransformation;
class KoColorSpace;
#include "KoColorConversionTransformation.h"
/**
* This class holds a cache of KoColorConversionTransformation.
*
* This class is not part of public API, and can be changed without notice.
*/
class KoColorConversionCache {
public:
class CachedTransformation;
public:
KoColorConversionCache();
~KoColorConversionCache();
/**
* This function return a cached color transformation if available
* or create one.
* @param src source color space
* @param dst destination color space
*/
KoCachedColorConversionTransformation cachedConverter(const KoColorSpace* src, const KoColorSpace* dst, KoColorConversionTransformation::Intent _renderingIntent);
/**
* This function is called by the destructor of the color space to
* warn the cache that any pointers to this color space is going to
* be invalid and that the cache needs to stop using those pointers.
* @param src source color space
*/
void colorSpaceIsDestroyed(const KoColorSpace* src);
private:
struct Private;
Private* const d;
};
/**
* This class hold a cached color conversion. It can only be created
* by the cache and when it's deleted it return the transformation to
* the pool of available color convertion transformation.
*
* This class is not part of public API, and can be changed without notice.
*/
class KoCachedColorConversionTransformation {
friend class KoColorConversionCache;
private:
KoCachedColorConversionTransformation(KoColorConversionCache* cache, KoColorConversionCache::CachedTransformation* transfo);
public:
KoCachedColorConversionTransformation(const KoCachedColorConversionTransformation&);
~KoCachedColorConversionTransformation();
public:
const KoColorConversionTransformation* transformation() const;
private:
struct Private;
Private* const d;
};
#endif
......@@ -36,6 +36,8 @@ class KoID;
* the color spaces. The most usefull functions are createColorConverter to create
* a color conversion between two color spaces, and insertColorSpace which is called
* by KoColorSpaceRegistry each time a new color space is added to the registry.
*
* This class is not part of public API, and can be changed without notice.
*/
class PIGMENTCMS_EXPORT KoColorConversionSystem {
public:
......
......@@ -53,3 +53,15 @@ KoColorConversionTransformation::Intent KoColorConversionTransformation::renderi
{
return d->renderingIntent;
}
void KoColorConversionTransformation::setSrcColorSpace(const KoColorSpace* cs) const
{
Q_ASSERT(*d->srcColorSpace == *cs);
d->srcColorSpace = cs;
}
void KoColorConversionTransformation::setDstColorSpace(const KoColorSpace* cs) const
{
Q_ASSERT(*d->dstColorSpace == *cs);
d->dstColorSpace = cs;
}
......@@ -25,11 +25,13 @@
#include <pigment_export.h>
class KoColorSpace;
class KoColorConversionCache;
/**
* This is the base class of all color transform that convert the color of a pixel
*/
class PIGMENTCMS_EXPORT KoColorConversionTransformation : KoColorTransformation{
friend class KoColorConversionCache;
struct Private;
public:
/**
......@@ -64,6 +66,9 @@ class PIGMENTCMS_EXPORT KoColorConversionTransformation : KoColorTransformation{
* @param nPixels the number of pixels in the buffers.
*/
virtual void transform(const quint8 *src, quint8 *dst, qint32 nPixels) const =0;
private:
void setSrcColorSpace(const KoColorSpace*) const;
void setDstColorSpace(const KoColorSpace*) const;
private:
Private * const d;
};
......
......@@ -28,6 +28,7 @@
#include "KoColorTransformation.h"
#include "KoColorTransformationFactory.h"
#include "KoColorTransformationFactoryRegistry.h"
#include "KoColorConversionCache.h"
#include "KoColorConversionSystem.h"
#include "KoColorSpaceRegistry.h"
#include "KoColorProfile.h"
......@@ -43,18 +44,12 @@ struct KoColorSpace::Private {
KoConvolutionOp* convolutionOp;
QThreadStorage< QVector<quint8>* > conversionCache;
mutable const KoColorSpace *lastUsedDstColorSpace;
mutable KoColorConversionTransformation* lastUsedTransform;
mutable KoColorConversionTransformation* transfoToRGBA16;
mutable KoColorConversionTransformation* transfoFromRGBA16;
mutable KoColorConversionTransformation* transfoToLABA16;
mutable KoColorConversionTransformation* transfoFromLABA16;
// cmsHTRANSFORM is a void *, so this should work.
typedef QMap<const KoColorSpace *, KoColorConversionTransformation*> TransformMap;
mutable TransformMap transforms; // Cache for existing transforms
};
KoColorSpace::KoColorSpace()
......@@ -69,8 +64,6 @@ KoColorSpace::KoColorSpace(const QString &id, const QString &name, KoMixColorsOp
d->name = name;
d->mixColorsOp = mixColorsOp;
d->convolutionOp = convolutionOp;
d->lastUsedDstColorSpace = 0;
d->lastUsedTransform = 0;
d->transfoToRGBA16 = 0;
d->transfoFromRGBA16 = 0;
d->transfoToLABA16 = 0;
......@@ -79,6 +72,7 @@ KoColorSpace::KoColorSpace(const QString &id, const QString &name, KoMixColorsOp
KoColorSpace::~KoColorSpace()
{
KoColorSpaceRegistry::instance()->colorConversionCache()->colorSpaceIsDestroyed(this);
delete d->mixColorsOp;
delete d->convolutionOp;
delete d;
......@@ -250,38 +244,8 @@ bool KoColorSpace::convertPixelsTo(const quint8 * src,
quint32 numPixels,
KoColorConversionTransformation::Intent renderingIntent) const
{
if (*dstColorSpace == *this)
{
if (src!= dst)
memcpy (dst, src, numPixels * this->pixelSize());
return true;
}
KoColorConversionTransformation* tf = 0;
#if 1
if (d->lastUsedTransform != 0 && d->lastUsedDstColorSpace != 0) {
if (*dstColorSpace == *d->lastUsedDstColorSpace) {
tf = d->lastUsedTransform;
}
}
if (not tf) {
if (!d->transforms.contains(dstColorSpace)) {
#endif // XXX: Should we clear the transform cache if it gets too big?
tf = this->createColorConverter(dstColorSpace, renderingIntent);
#if 1
d->transforms[dstColorSpace] = tf;
}
else {
tf = d->transforms[dstColorSpace];
}
d->lastUsedTransform = tf;
d->lastUsedDstColorSpace = dstColorSpace;
}
#endif
tf->transform(src, dst, numPixels);
KoCachedColorConversionTransformation cct = KoColorSpaceRegistry::instance()->colorConversionCache()->cachedConverter(this, dstColorSpace, renderingIntent);
cct.transformation()->transform(src, dst, numPixels);
return true;
}
......
......@@ -35,6 +35,7 @@
#include "KoPluginLoader.h"
#include "KoColorSpace.h"
#include "KoColorConversionCache.h"
#include "KoColorConversionSystem.h"
#include "KoBasicHistogramProducers.h"
......@@ -51,6 +52,7 @@ struct KoColorSpaceRegistry::Private {
QMap<QString, PaintActionList> paintDevActionMap;
const KoColorSpace *alphaCs;
KoColorConversionSystem *colorConversionSystem;
KoColorConversionCache* colorConversionCache;
static KoColorSpaceRegistry *singleton;
};
......@@ -70,6 +72,7 @@ KoColorSpaceRegistry* KoColorSpaceRegistry::instance()
void KoColorSpaceRegistry::init()
{
d->colorConversionSystem = new KoColorConversionSystem;
d->colorConversionCache = new KoColorConversionCache;
// prepare a list of the profiles
KGlobal::mainComponent().dirs()->addResourceType("icc_profiles", 0, "share/color/icc/");
......@@ -144,11 +147,13 @@ void KoColorSpaceRegistry::init()
KoColorSpaceRegistry::KoColorSpaceRegistry() : d(new Private())
{
d->colorConversionSystem = 0;
d->colorConversionCache = 0;
}
KoColorSpaceRegistry::~KoColorSpaceRegistry()
{
delete d->colorConversionSystem;
delete d->colorConversionCache;
delete d;
}
......@@ -389,4 +394,9 @@ const KoColorConversionSystem* KoColorSpaceRegistry::colorConversionSystem() con
return d->colorConversionSystem;
}
KoColorConversionCache* KoColorSpaceRegistry::colorConversionCache() const
{
return d->colorConversionCache;
}
#include "KoColorSpaceRegistry.moc"
......@@ -34,6 +34,7 @@ class KoColorSpace;
class KoColorSpaceFactory;
class KoColorProfile;
class KoColorConversionSystem;
class KoColorConversionCache;
// XXX: USE STATIC DELETER! USE STATIC DELETER!
......@@ -242,6 +243,11 @@ public:
*/
const KoColorConversionSystem* colorConversionSystem() const;
/**
* @return the cache of color conversion transformation to be use by KoColorSpace
*/
KoColorConversionCache* colorConversionCache() const;
private:
bool isCached(QString csId, QString profileName) const;
QString idsToCacheName(QString csId, QString profileName) const;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment