Reduce SkMaskGamma cache thrashing.

https://codereview.appspot.com/6497114/


git-svn-id: http://skia.googlecode.com/svn/trunk@5492 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
bungeman@google.com 2012-09-11 18:44:55 +00:00
parent fb3dd3a6f5
commit ae30f56019
4 changed files with 58 additions and 17 deletions

View File

@ -36,14 +36,22 @@ SkGammaLuminance::SkGammaLuminance(SkScalar gamma)
, fGammaInverse(SkScalarInvert(gamma)) {
}
float SkGammaLuminance::toLuma(SkScalar luminance) const {
SkScalar SkGammaLuminance::toLuma(SkScalar luminance) const {
return SkScalarPow(luminance, fGamma);
}
float SkGammaLuminance::fromLuma(SkScalar luma) const {
SkScalar SkGammaLuminance::fromLuma(SkScalar luma) const {
return SkScalarPow(luma, fGammaInverse);
}
SkScalar SkLinearLuminance::toLuma(SkScalar luminance) const {
return luminance;
}
SkScalar SkLinearLuminance::fromLuma(SkScalar luma) const {
return luma;
}
static float apply_contrast(float srca, float contrast) {
return srca + ((1.0f - srca) * contrast * srca);
}

View File

@ -58,6 +58,12 @@ private:
SkScalar fGammaInverse;
};
class SkLinearLuminance : public SkColorSpaceLuminance {
public:
SkScalar toLuma(SkScalar luminance) const SK_OVERRIDE;
SkScalar fromLuma(SkScalar luma) const SK_OVERRIDE;
};
///@{
/**
* Scales base <= 2^N-1 to 2^8-1
@ -107,6 +113,9 @@ template <int R_LUM_BITS, int G_LUM_BITS, int B_LUM_BITS> class SkTMaskGamma : p
public:
SK_DECLARE_INST_COUNT_TEMPLATE(SkTMaskGamma)
SkTMaskGamma() : fIsLinear(true) {
}
/**
* Creates tables to convert linear alpha values to gamma correcting alpha
* values.
@ -118,7 +127,7 @@ public:
*/
SkTMaskGamma(SkScalar contrast,
const SkColorSpaceLuminance& paint,
const SkColorSpaceLuminance& device) {
const SkColorSpaceLuminance& device) : fIsLinear(false) {
for (U8CPU i = 0; i < (1 << kLuminanceBits_Max); ++i) {
U8CPU lum = sk_t_scale255<kLuminanceBits_Max>(i);
SkTMaskGamma_build_correcting_lut(fGammaTables[i], lum, contrast, paint, device);
@ -126,7 +135,7 @@ public:
}
/** Given a color, returns the closest cannonical color. */
SkColor cannonicalColor(SkColor color) {
static SkColor cannonicalColor(SkColor color) {
return SkColorSetRGB(
sk_t_scale255<kLuminanceBits_R>(SkColorGetR(color) >> (8 - kLuminanceBits_R)),
sk_t_scale255<kLuminanceBits_G>(SkColorGetG(color) >> (8 - kLuminanceBits_G)),
@ -153,6 +162,7 @@ private:
: (R_LUM_BITS > G_LUM_BITS ? R_LUM_BITS : G_LUM_BITS)
};
uint8_t fGammaTables[1 << kLuminanceBits_Max][256];
bool fIsLinear;
typedef SkRefCnt INHERITED;
};
@ -167,6 +177,9 @@ SK_DEFINE_INST_COUNT_TEMPLATE(
* SkTMaskPreBlend is a tear-off of SkTMaskGamma. It provides the tables to
* convert a linear alpha value for a given channel to a gamma correcting alpha
* value for that channel. This class is immutable.
*
* If fR, fG, or fB is NULL, all of them will be. This indicates that no mask
* pre blend should be applied.
*/
template <int R_LUM_BITS, int G_LUM_BITS, int B_LUM_BITS> class SkTMaskPreBlend {
private:
@ -175,7 +188,7 @@ private:
const uint8_t* g,
const uint8_t* b)
: fParent(parent), fR(r), fG(g), fB(b) {
parent->ref();
SkSafeRef(parent);
}
SkAutoTUnref<SkTMaskGamma<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS> > fParent;
friend class SkTMaskGamma<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>;
@ -186,7 +199,7 @@ public:
*/
SkTMaskPreBlend(const SkTMaskPreBlend<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>& that)
: fParent(that.fParent.get()), fR(that.fR), fG(that.fG), fB(that.fB) {
fParent.get()->ref();
SkSafeRef(fParent.get());
}
~SkTMaskPreBlend() { }
const uint8_t* fR;
@ -197,7 +210,9 @@ public:
template <int R_LUM_BITS, int G_LUM_BITS, int B_LUM_BITS>
SkTMaskPreBlend<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>
SkTMaskGamma<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>::preBlend(SkColor color) {
return SkTMaskPreBlend<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>(
return fIsLinear ? SkTMaskPreBlend<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>(
NULL, NULL, NULL, NULL)
: SkTMaskPreBlend<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>(
this,
fGammaTables[SkColorGetR(color) >> (8 - kLuminanceBits_Max)],
fGammaTables[SkColorGetG(color) >> (8 - kLuminanceBits_Max)],

View File

@ -1621,6 +1621,8 @@ void SkScalerContext::MakeRec(const SkPaint& paint,
*/
SK_DECLARE_STATIC_MUTEX(gMaskGammaCacheMutex);
static SkColorSpaceLuminance* gLinearLuminance = NULL;
static SkColorSpaceLuminance* gDeviceLuminance = NULL;
static SkScalar gDeviceGammaExponent = SK_ScalarMin;
/**
@ -1628,6 +1630,12 @@ static SkScalar gDeviceGammaExponent = SK_ScalarMin;
* the returned SkColorSpaceLuminance pointer is forgotten.
*/
static SkColorSpaceLuminance* cachedDeviceLuminance(SkScalar gammaExponent) {
if (SK_Scalar1 == gammaExponent) {
if (NULL == gLinearLuminance) {
gLinearLuminance = SkNEW(SkLinearLuminance);
}
return gLinearLuminance;
}
if (gDeviceGammaExponent != gammaExponent) {
SkDELETE(gDeviceLuminance);
if (0 == gammaExponent) {
@ -1647,6 +1655,12 @@ static SkScalar gPaintGammaExponent = SK_ScalarMin;
* the returned SkColorSpaceLuminance pointer is forgotten.
*/
static SkColorSpaceLuminance* cachedPaintLuminance(SkScalar gammaExponent) {
if (SK_Scalar1 == gammaExponent) {
if (NULL == gLinearLuminance) {
gLinearLuminance = SkNEW(SkLinearLuminance);
}
return gLinearLuminance;
}
if (gPaintGammaExponent != gammaExponent) {
SkDELETE(gPaintLuminance);
if (0 == gammaExponent) {
@ -1659,6 +1673,7 @@ static SkColorSpaceLuminance* cachedPaintLuminance(SkScalar gammaExponent) {
return gPaintLuminance;
}
static SkMaskGamma* gLinearMaskGamma = NULL;
static SkMaskGamma* gMaskGamma = NULL;
static SkScalar gContrast = SK_ScalarMin;
static SkScalar gPaintGamma = SK_ScalarMin;
@ -1668,6 +1683,12 @@ static SkScalar gDeviceGamma = SK_ScalarMin;
* the returned SkMaskGamma pointer is refed or forgotten.
*/
static SkMaskGamma* cachedMaskGamma(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma) {
if (0 == contrast && SK_Scalar1 == paintGamma && SK_Scalar1 == deviceGamma) {
if (NULL == gLinearMaskGamma) {
gLinearMaskGamma = SkNEW(SkMaskGamma);
}
return gLinearMaskGamma;
}
if (gContrast != contrast || gPaintGamma != paintGamma || gDeviceGamma != deviceGamma) {
SkSafeUnref(gMaskGamma);
SkColorSpaceLuminance* paintLuminance = cachedPaintLuminance(paintGamma);
@ -1683,11 +1704,15 @@ static SkMaskGamma* cachedMaskGamma(SkScalar contrast, SkScalar paintGamma, SkSc
/*static*/ void SkPaint::Term() {
SkAutoMutexAcquire ama(gMaskGammaCacheMutex);
SkSafeUnref(gLinearMaskGamma);
SkSafeUnref(gMaskGamma);
SkDEBUGCODE(gContrast = SK_ScalarMin;)
SkDEBUGCODE(gPaintGamma = SK_ScalarMin;)
SkDEBUGCODE(gDeviceGamma = SK_ScalarMin;)
SkDELETE(gLinearLuminance);
SkDELETE(gPaintLuminance);
SkDEBUGCODE(gPaintLuminance = NULL;)
SkDEBUGCODE(gPaintGammaExponent = SK_ScalarMin;)
@ -1711,11 +1736,7 @@ void SkScalerContext::PostMakeRec(const SkPaint& paint, SkScalerContext::Rec* re
case SkMask::kLCD32_Format: {
// filter down the luminance color to a finite number of bits
SkColor color = rec->getLuminanceColor();
SkAutoMutexAcquire ama(gMaskGammaCacheMutex);
SkMaskGamma* maskGamma = cachedMaskGamma(rec->getContrast(),
rec->getPaintGamma(),
rec->getDeviceGamma());
rec->setLuminanceColor(maskGamma->cannonicalColor(color));
rec->setLuminanceColor(SkMaskGamma::cannonicalColor(color));
break;
}
case SkMask::kA8_Format: {
@ -1732,11 +1753,8 @@ void SkScalerContext::PostMakeRec(const SkPaint& paint, SkScalerContext::Rec* re
}
// reduce to our finite number of bits
SkMaskGamma* maskGamma = cachedMaskGamma(rec->getContrast(),
rec->getPaintGamma(),
rec->getDeviceGamma());
color = SkColorSetRGB(lum, lum, lum);
rec->setLuminanceColor(maskGamma->cannonicalColor(color));
rec->setLuminanceColor(SkMaskGamma::cannonicalColor(color));
break;
}
case SkMask::kBW_Format:

View File

@ -491,7 +491,7 @@ static void applyLUTToA8Glyph(const SkGlyph& glyph, const uint8_t* lut) {
void SkScalerContext::getImage(const SkGlyph& origGlyph) {
const SkGlyph* glyph = &origGlyph;
SkGlyph tmpGlyph;
SkMaskGamma::PreBlend* maskPreBlend = &fMaskPreBlend;
SkMaskGamma::PreBlend* maskPreBlend = fMaskPreBlend.fParent ? &fMaskPreBlend : NULL;
if (fMaskFilter) { // restore the prefilter bounds
tmpGlyph.init(origGlyph.fID);