Commit e3b582f8 authored by Boudewijn Rempt's avatar Boudewijn Rempt

Make the colorspace threadsafe.

svn path=/trunk/koffice/; revision=645763
parent 3122968e
......@@ -16,6 +16,8 @@
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <QThreadStorage>
#include <QByteArray>
#include "KoColorSpace.h"
......@@ -32,8 +34,9 @@ struct KoColorSpace::Private {
Q3ValueVector<KoChannelInfo *> channels;
KoMixColorsOp* mixColorsOp;
KoConvolutionOp* convolutionOp;
mutable Q3MemArray<quint8> conversionCache; // XXX: This will be a bad problem when we have threading.
DWORD cmType; // The colorspace type as defined by littlecms
QThreadStorage< QVector<quint8>* > conversionCache;
DWORD cmType; // The colorspace type as defined by littlecms
icColorSpaceSignature colorSpaceSignature; // The colorspace signature as defined in icm/icc files
};
......@@ -184,17 +187,17 @@ void KoColorSpace::bitBlt(quint8 *dst,
}
void KoColorSpace::bitBlt(quint8 *dst,
qint32 dststride,
KoColorSpace * srcSpace,
const quint8 *src,
qint32 srcRowStride,
const quint8 *srcAlphaMask,
qint32 maskRowStride,
quint8 opacity,
qint32 rows,
qint32 cols,
const KoCompositeOp * op,
const QBitArray & channelFlags) const
qint32 dststride,
KoColorSpace * srcSpace,
const quint8 *src,
qint32 srcRowStride,
const quint8 *srcAlphaMask,
qint32 maskRowStride,
quint8 opacity,
qint32 rows,
qint32 cols,
const KoCompositeOp * op,
const QBitArray & channelFlags) const
{
if (rows <= 0 || cols <= 0)
return;
......@@ -202,16 +205,12 @@ void KoColorSpace::bitBlt(quint8 *dst,
if (this != srcSpace) {
quint32 len = pixelSize() * rows * cols;
// If our conversion cache is too small, extend it.
if (!d->conversionCache.resize( len, Q3GArray::SpeedOptim )) {
kWarning() << "Could not allocate enough memory for the conversion!\n";
// XXX: We should do a slow, pixel by pixel bitblt here...
abort();
}
QVector<quint8> * conversionCache = threadLocalConversionCache(len);
quint8* conversionData = conversionCache->data();
for (qint32 row = 0; row < rows; row++) {
srcSpace->convertPixelsTo(src + row * srcRowStride,
d->conversionCache.data() + row * cols * pixelSize(), this,
conversionData + row * cols * pixelSize(), this,
cols);
}
......@@ -219,7 +218,7 @@ void KoColorSpace::bitBlt(quint8 *dst,
srcRowStride = cols * pixelSize();
op->composite( dst, dststride,
d->conversionCache.data(), srcRowStride,
conversionData, srcRowStride,
srcAlphaMask, maskRowStride,
rows, cols,
opacity, channelFlags );
......@@ -238,16 +237,16 @@ void KoColorSpace::bitBlt(quint8 *dst,
// extra function call in this critical section of code. What to
// do?
void KoColorSpace::bitBlt(quint8 *dst,
qint32 dststride,
KoColorSpace * srcSpace,
const quint8 *src,
qint32 srcRowStride,
const quint8 *srcAlphaMask,
qint32 maskRowStride,
quint8 opacity,
qint32 rows,
qint32 cols,
const KoCompositeOp * op) const
qint32 dststride,
KoColorSpace * srcSpace,
const quint8 *src,
qint32 srcRowStride,
const quint8 *srcAlphaMask,
qint32 maskRowStride,
quint8 opacity,
qint32 rows,
qint32 cols,
const KoCompositeOp * op) const
{
if (rows <= 0 || cols <= 0)
return;
......@@ -255,16 +254,12 @@ void KoColorSpace::bitBlt(quint8 *dst,
if (this != srcSpace) {
quint32 len = pixelSize() * rows * cols;
// If our conversion cache is too small, extend it.
if (!d->conversionCache.resize( len, Q3GArray::SpeedOptim )) {
kWarning() << "Could not allocate enough memory for the conversion!\n";
// XXX: We should do a slow, pixel by pixel bitblt here...
abort();
}
QVector<quint8> * conversionCache = threadLocalConversionCache(len);
quint8* conversionData = conversionCache->data();
for (qint32 row = 0; row < rows; row++) {
srcSpace->convertPixelsTo(src + row * srcRowStride,
d->conversionCache.data() + row * cols * pixelSize(), this,
conversionData + row * cols * pixelSize(), this,
cols);
}
......@@ -272,7 +267,7 @@ void KoColorSpace::bitBlt(quint8 *dst,
srcRowStride = cols * pixelSize();
op->composite( dst, dststride,
d->conversionCache.data(), srcRowStride,
conversionData, srcRowStride,
srcAlphaMask, maskRowStride,
rows, cols,
opacity);
......@@ -286,3 +281,18 @@ void KoColorSpace::bitBlt(quint8 *dst,
opacity);
}
}
QVector<quint8> * KoColorSpace::threadLocalConversionCache(quint32 size) const
{
QVector<quint8> * ba = 0;
if ( !d->conversionCache.hasLocalData() ) {
ba = new QVector<quint8>( '0', size );
d->conversionCache.setLocalData( ba );
}
else {
ba = d->conversionCache.localData();
if ( ( quint8 )ba->size() < size )
ba->resize( size );
}
return ba;
}
......@@ -24,10 +24,9 @@
#include <limits.h>
#include <QImage>
#include <QBitArray>
#include <QHash>
#include <QVector>
#include <Q3MemArray>
#include <q3valuevector.h>
#include <q3valuelist.h>
......@@ -36,6 +35,7 @@
#include <KoID.h>
#include <pigment_export.h>
class KoCompositeOp;
class KoColorProfile;
class KoColorSpaceRegistry;
......@@ -592,6 +592,13 @@ protected:
*/
virtual void addChannel(KoChannelInfo * ci);
private:
/**
* Returns the thread-local conversion cache. If it doesn't exist
* yet, it is created. If it is currently too small, it is resized.
*/
QVector<quint8> * threadLocalConversionCache(quint32 size) const;
class Private;
Private * const d;
};
......
......@@ -118,12 +118,12 @@ namespace {
} else {
memset(dst, 0, sizeof(typename _CSTraits::channels_type) * _CSTraits::channels_nb);
}
}
};
template<class _CSTraits>
class KoConvolutionOpImpl : public KoConvolutionOp{
class KoConvolutionOpImpl : public KoConvolutionOp {
public:
KoConvolutionOpImpl() { }
virtual ~KoConvolutionOpImpl() { }
......@@ -143,7 +143,7 @@ namespace {
}
totalAlpha += alphaTimesWeight;
}
if (channelFlags & KoChannelInfo::FLAG_COLOR) {
typename _CSTraits::channels_type* dstColor = _CSTraits::nativeArray(dst);
for(uint i = 0; i < _CSTraits::channels_nb; i++)
......@@ -151,7 +151,7 @@ namespace {
typename KoColorSpaceMathsTraits<typename _CSTraits::channels_type>::compositetype v = totals[i] / factor + offset;
dstColor[ i ] = CLAMP(v, KoColorSpaceMathsTraits<typename _CSTraits::channels_type>::min, KoColorSpaceMathsTraits<typename _CSTraits::channels_type>::max);
}
}
if (channelFlags & KoChannelInfo::FLAG_ALPHA) {
_CSTraits::setAlpha(dst, CLAMP((totalAlpha/ factor) + offset, 0, 0xFF ),1);
......@@ -202,7 +202,7 @@ class KoColorSpaceAbstract : public KoColorSpace {
{
this->addCompositeOp( new CompositeCopy( this ) );
};
virtual quint32 colorChannelCount() const { return _CSTraits::channels_nb - 1; }
virtual quint32 channelCount() const { return _CSTraits::channels_nb; };
virtual quint32 pixelSize() const { return _CSTraits::pixelSize; }
......@@ -220,7 +220,7 @@ class KoColorSpaceAbstract : public KoColorSpace {
typename _CSTraits::channels_type c = _CSTraits::nativeArray(pixel)[channelIndex];
return QString().setNum( 100. * ((double)c ) / KoColorSpaceMathsTraits<typename _CSTraits::channels_type>::max);
}
virtual quint8 scaleToU8(const quint8 * srcPixel, qint32 channelIndex) const {
typename _CSTraits::channels_type c = _CSTraits::nativeArray(srcPixel)[channelIndex];
return KoColorSpaceMaths<typename _CSTraits::channels_type, quint8>::scaleToA(c);
......@@ -276,7 +276,7 @@ class KoColorSpaceAbstract : public KoColorSpace {
*alphapixel = KoColorSpaceMaths<typename _CSTraits::channels_type>::multiply( *alphapixel, valpha );
}
}
virtual void applyInverseAlphaU8Mask(quint8 * pixels, const quint8 * alpha, qint32 nPixels) const
{
if (_CSTraits::alpha_pos < 0) return;
......@@ -288,7 +288,7 @@ class KoColorSpaceAbstract : public KoColorSpace {
*alphapixel = KoColorSpaceMaths<typename _CSTraits::channels_type>::multiply( *alphapixel, valpha );
}
}
virtual quint8 intensity8(const quint8 * src) const
{
QColor c;
......
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