Fix GPU text colors when color spaces are involved
1) Only store GrColors in GrTextUtils::Paint. We still store
premul and unpremul versions, but this is slightly clearer.
2) GrTextUtils::Paint also needs info from the render target
context to linearize and transform the color to dst space.
Bug: skia:6605
Change-Id: I6e12c55eafaecd2a090c82b4f56827401305bf3a
Reviewed-on: https://skia-review.googlesource.com/16486
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
diff --git a/src/gpu/ops/GrAtlasTextOp.cpp b/src/gpu/ops/GrAtlasTextOp.cpp
index 5271d42..f902cce 100644
--- a/src/gpu/ops/GrAtlasTextOp.cpp
+++ b/src/gpu/ops/GrAtlasTextOp.cpp
@@ -20,12 +20,14 @@
///////////////////////////////////////////////////////////////////////////////////////////////////
-static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
- unsigned r = SkColorGetR(c);
- unsigned g = SkColorGetG(c);
- unsigned b = SkColorGetB(c);
- return GrColorPackRGBA(r, g, b, 0xff);
+#ifdef SK_GAMMA_APPLY_TO_A8
+static inline SkColor unpremultiplied_grcolor_to_skcolor(GrColor c) {
+ unsigned r = GrColorUnpackR(c);
+ unsigned g = GrColorUnpackG(c);
+ unsigned b = GrColorUnpackB(c);
+ return SkColorSetRGB(r, g, b);
}
+#endif
static const int kDistanceAdjustLumShift = 5;
@@ -227,7 +229,7 @@
// TODO trying to figure out why lcd is so whack
sk_sp<GrGeometryProcessor> GrAtlasTextOp::setupDfProcessor(GrResourceProvider* resourceProvider,
const SkMatrix& viewMatrix,
- SkColor filteredColor,
+ GrColor filteredColor,
GrColor color,
sk_sp<GrTextureProxy> proxy) const {
GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kBilerp_FilterMode);
@@ -242,16 +244,14 @@
flags |= kUseLCD_DistanceFieldEffectFlag;
flags |= fUseBGR ? kBGR_DistanceFieldEffectFlag : 0;
- GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor);
-
float redCorrection = fDistanceAdjustTable->getAdjustment(
- GrColorUnpackR(colorNoPreMul) >> kDistanceAdjustLumShift,
+ GrColorUnpackR(filteredColor) >> kDistanceAdjustLumShift,
fUseGammaCorrectDistanceTable);
float greenCorrection = fDistanceAdjustTable->getAdjustment(
- GrColorUnpackG(colorNoPreMul) >> kDistanceAdjustLumShift,
+ GrColorUnpackG(filteredColor) >> kDistanceAdjustLumShift,
fUseGammaCorrectDistanceTable);
float blueCorrection = fDistanceAdjustTable->getAdjustment(
- GrColorUnpackB(colorNoPreMul) >> kDistanceAdjustLumShift,
+ GrColorUnpackB(filteredColor) >> kDistanceAdjustLumShift,
fUseGammaCorrectDistanceTable);
GrDistanceFieldLCDTextGeoProc::DistanceAdjust widthAdjust =
GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(
@@ -263,7 +263,9 @@
this->usesLocalCoords());
} else {
#ifdef SK_GAMMA_APPLY_TO_A8
- U8CPU lum = SkColorSpaceLuminance::computeLuminance(SK_GAMMA_EXPONENT, filteredColor);
+ SkColor filteredSkColor = unpremultiplied_grcolor_to_skcolor(filteredColor);
+
+ U8CPU lum = SkColorSpaceLuminance::computeLuminance(SK_GAMMA_EXPONENT, filteredSkColor);
float correction = fDistanceAdjustTable->getAdjustment(lum >> kDistanceAdjustLumShift,
fUseGammaCorrectDistanceTable);
return GrDistanceFieldA8TextGeoProc::Make(resourceProvider, color,
diff --git a/src/gpu/ops/GrAtlasTextOp.h b/src/gpu/ops/GrAtlasTextOp.h
index 8b65fb9..ac59d4c 100644
--- a/src/gpu/ops/GrAtlasTextOp.h
+++ b/src/gpu/ops/GrAtlasTextOp.h
@@ -64,7 +64,7 @@
static std::unique_ptr<GrAtlasTextOp> MakeDistanceField(
int glyphCount, GrAtlasGlyphCache* fontCache,
const GrDistanceFieldAdjustTable* distanceAdjustTable,
- bool useGammaCorrectDistanceTable, SkColor filteredColor, bool isLCD, bool useBGR) {
+ bool useGammaCorrectDistanceTable, GrColor filteredColor, bool isLCD, bool useBGR) {
std::unique_ptr<GrAtlasTextOp> op(new GrAtlasTextOp);
op->fFontCache = fontCache;
@@ -150,7 +150,7 @@
// TODO just use class params
// TODO trying to figure out why lcd is so whack
sk_sp<GrGeometryProcessor> setupDfProcessor(GrResourceProvider*,
- const SkMatrix& viewMatrix, SkColor filteredColor,
+ const SkMatrix& viewMatrix, GrColor filteredColor,
GrColor color, sk_sp<GrTextureProxy> proxy) const;
GrColor fColor;
@@ -175,7 +175,7 @@
// Distance field properties
sk_sp<const GrDistanceFieldAdjustTable> fDistanceAdjustTable;
- SkColor fFilteredColor;
+ GrColor fFilteredColor;
bool fUseGammaCorrectDistanceTable;
friend class GrBlobRegenHelper; // Needs to trigger flushes
diff --git a/src/gpu/text/GrAtlasTextBlob.cpp b/src/gpu/text/GrAtlasTextBlob.cpp
index d3aa7e4..be9bb27 100644
--- a/src/gpu/text/GrAtlasTextBlob.cpp
+++ b/src/gpu/text/GrAtlasTextBlob.cpp
@@ -179,7 +179,7 @@
// to regenerate the blob on any color change
// We use the grPaint to get any color filter effects
if (fKey.fCanonicalColor == SK_ColorTRANSPARENT &&
- fFilteredPaintColor != paint.filteredSkColor()) {
+ fFilteredPaintColor != paint.filteredUnpremulColor()) {
return true;
}
@@ -266,7 +266,7 @@
std::unique_ptr<GrAtlasTextOp> op;
if (info.drawAsDistanceFields()) {
- SkColor filteredColor = paint.filteredSkColor();
+ GrColor filteredColor = paint.filteredUnpremulColor();
bool useBGR = SkPixelGeometryIsBGR(props.pixelGeometry());
op = GrAtlasTextOp::MakeDistanceField(glyphCount, cache, distanceAdjustTable,
useGammaCorrectDistanceTable, filteredColor,
@@ -280,7 +280,7 @@
geometry.fRun = run;
geometry.fSubRun = subRun;
geometry.fColor =
- info.maskFormat() == kARGB_GrMaskFormat ? GrColor_WHITE : paint.filteredPremulGrColor();
+ info.maskFormat() == kARGB_GrMaskFormat ? GrColor_WHITE : paint.filteredPremulColor();
geometry.fX = x;
geometry.fY = y;
op->init();
diff --git a/src/gpu/text/GrAtlasTextBlob.h b/src/gpu/text/GrAtlasTextBlob.h
index 855413b..4cc1028 100644
--- a/src/gpu/text/GrAtlasTextBlob.h
+++ b/src/gpu/text/GrAtlasTextBlob.h
@@ -240,7 +240,7 @@
// The color here is the GrPaint color, and it is used to determine whether we
// have to regenerate LCD text blobs.
// We use this color vs the SkPaint color because it has the colorfilter applied.
- void initReusableBlob(SkColor filteredColor, const SkMatrix& viewMatrix, SkScalar x,
+ void initReusableBlob(GrColor filteredColor, const SkMatrix& viewMatrix, SkScalar x,
SkScalar y) {
fFilteredPaintColor = filteredColor;
this->setupViewMatrix(viewMatrix, x, y);
@@ -530,7 +530,7 @@
SkMatrix fInitialViewMatrix;
SkMatrix fInitialViewMatrixInverse;
size_t fSize;
- SkColor fFilteredPaintColor;
+ GrColor fFilteredPaintColor;
SkScalar fInitialX;
SkScalar fInitialY;
diff --git a/src/gpu/text/GrAtlasTextContext.cpp b/src/gpu/text/GrAtlasTextContext.cpp
index d99f282..abe8d24 100644
--- a/src/gpu/text/GrAtlasTextContext.cpp
+++ b/src/gpu/text/GrAtlasTextContext.cpp
@@ -118,7 +118,7 @@
cacheBlob = cache->find(key);
}
- GrTextUtils::Paint paint(&skPaint);
+ GrTextUtils::Paint paint(&skPaint, rtc->getColorSpace(), rtc->getColorXformFromSRGB());
if (cacheBlob) {
if (cacheBlob->mustRegenerate(paint, blurRec, viewMatrix, x, y)) {
// We have to remake the blob because changes may invalidate our masks.
@@ -166,7 +166,7 @@
uint32_t scalerContextFlags, const SkMatrix& viewMatrix,
const SkSurfaceProps& props, const SkTextBlob* blob,
SkScalar x, SkScalar y, SkDrawFilter* drawFilter) {
- cacheBlob->initReusableBlob(paint.filteredSkColor(), viewMatrix, x, y);
+ cacheBlob->initReusableBlob(paint.filteredUnpremulColor(), viewMatrix, x, y);
// Regenerate textblob
SkTextBlobRunIterator it(blob);
@@ -289,7 +289,7 @@
if (context->abandoned()) {
return;
}
- GrTextUtils::Paint paint(&skPaint);
+ GrTextUtils::Paint paint(&skPaint, rtc->getColorSpace(), rtc->getColorXformFromSRGB());
if (this->canDraw(skPaint, viewMatrix, props, *context->caps()->shaderCaps())) {
sk_sp<GrAtlasTextBlob> blob(
MakeDrawTextBlob(context->getTextBlobCache(), context->getAtlasGlyphCache(),
@@ -313,7 +313,7 @@
const char text[], size_t byteLength, const SkScalar pos[],
int scalarsPerPosition, const SkPoint& offset,
const SkIRect& regionClipBounds) {
- GrTextUtils::Paint paint(&skPaint);
+ GrTextUtils::Paint paint(&skPaint, rtc->getColorSpace(), rtc->getColorXformFromSRGB());
if (context->abandoned()) {
return;
} else if (this->canDraw(skPaint, viewMatrix, props, *context->caps()->shaderCaps())) {
@@ -352,7 +352,7 @@
}
// Setup dummy SkPaint / GrPaint / GrRenderTargetContext
- sk_sp<GrRenderTargetContext> renderTargetContext(context->makeDeferredRenderTargetContext(
+ sk_sp<GrRenderTargetContext> rtc(context->makeDeferredRenderTargetContext(
SkBackingFit::kApprox, 1024, 1024, kRGBA_8888_GrPixelConfig, nullptr));
SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
@@ -374,7 +374,7 @@
SkScalar x = SkIntToScalar(xInt);
SkScalar y = SkIntToScalar(yInt);
- GrTextUtils::Paint paint(&skPaint);
+ GrTextUtils::Paint paint(&skPaint, rtc->getColorSpace(), rtc->getColorXformFromSRGB());
// right now we don't handle textblobs, nor do we handle drawPosText. Since we only intend to
// test the text op with this unit test, that is okay.
sk_sp<GrAtlasTextBlob> blob(GrAtlasTextContext::MakeDrawTextBlob(
diff --git a/src/gpu/text/GrStencilAndCoverTextContext.cpp b/src/gpu/text/GrStencilAndCoverTextContext.cpp
index 0ae4023..65889b2 100644
--- a/src/gpu/text/GrStencilAndCoverTextContext.cpp
+++ b/src/gpu/text/GrStencilAndCoverTextContext.cpp
@@ -134,7 +134,7 @@
SkScalar x, SkScalar y,
SkDrawFilter* drawFilter,
const SkIRect& clipBounds) {
- GrTextUtils::Paint paint(&skPaint);
+ GrTextUtils::Paint paint(&skPaint, rtc->getColorSpace(), rtc->getColorXformFromSRGB());
GrTextUtils::RunPaint runPaint(&paint, drawFilter, props);
SkTextBlobRunIterator it(blob);
for (;!it.done(); it.next()) {
diff --git a/src/gpu/text/GrTextUtils.cpp b/src/gpu/text/GrTextUtils.cpp
index 31d0291..9baf341 100644
--- a/src/gpu/text/GrTextUtils.cpp
+++ b/src/gpu/text/GrTextUtils.cpp
@@ -50,6 +50,27 @@
}
}
+void GrTextUtils::Paint::initFilteredColor() {
+ // This mirrors the logic in skpaint_to_grpaint_impl for handling paint colors
+ if (fDstColorSpace) {
+ GrColor4f filteredColor = SkColorToUnpremulGrColor4f(fPaint->getColor(), fDstColorSpace,
+ fColorXformFromSRGB);
+ if (fPaint->getColorFilter()) {
+ filteredColor = GrColor4f::FromSkColor4f(
+ fPaint->getColorFilter()->filterColor4f(filteredColor.toSkColor4f()));
+ }
+ fFilteredPremulColor = filteredColor.premul().toGrColor();
+ fFilteredUnpremulColor = filteredColor.toGrColor();
+ } else {
+ SkColor filteredSkColor = fPaint->getColor();
+ if (fPaint->getColorFilter()) {
+ filteredSkColor = fPaint->getColorFilter()->filterColor(filteredSkColor);
+ }
+ fFilteredPremulColor = SkColorToPremulGrColor(filteredSkColor);
+ fFilteredUnpremulColor = SkColorToUnpremulGrColor(filteredSkColor);
+ }
+}
+
bool GrTextUtils::RunPaint::modifyForRun(const SkTextBlobRunIterator& run) {
if (!fModifiedPaint.isValid()) {
fModifiedPaint.init(fOriginalPaint->skPaint());
@@ -99,7 +120,7 @@
BmpAppendGlyph(
blob, runIndex, fontCache, &currStrike, glyph,
SkScalarFloorToInt(position.fX), SkScalarFloorToInt(position.fY),
- paint.filteredPremulGrColor(), cache);
+ paint.filteredPremulColor(), cache);
}
);
@@ -135,7 +156,7 @@
BmpAppendGlyph(
blob, runIndex, fontCache, &currStrike, glyph,
SkScalarFloorToInt(position.fX), SkScalarFloorToInt(position.fY),
- paint.filteredPremulGrColor(), cache);
+ paint.filteredPremulColor(), cache);
}
);
@@ -390,7 +411,7 @@
SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0);
if (!DfAppendGlyph(blob, runIndex, fontCache, &currStrike, glyph, x, y,
- paint.filteredPremulGrColor(), cache, textRatio, viewMatrix)) {
+ paint.filteredPremulColor(), cache, textRatio, viewMatrix)) {
// couldn't append, send to fallback
fallbackTxt.append(SkToInt(text-lastText), lastText);
*fallbackPos.append() = pos[0];
@@ -417,7 +438,7 @@
SkScalar advanceY = SkFloatToScalar(glyph.fAdvanceY) * alignMul * textRatio;
if (!DfAppendGlyph(blob, runIndex, fontCache, &currStrike, glyph, x - advanceX,
- y - advanceY, paint.filteredPremulGrColor(), cache, textRatio,
+ y - advanceY, paint.filteredPremulColor(), cache, textRatio,
viewMatrix)) {
// couldn't append, send to fallback
fallbackTxt.append(SkToInt(text-lastText), lastText);
diff --git a/src/gpu/text/GrTextUtils.h b/src/gpu/text/GrTextUtils.h
index c5daa42..9f38699 100644
--- a/src/gpu/text/GrTextUtils.h
+++ b/src/gpu/text/GrTextUtils.h
@@ -19,10 +19,12 @@
class GrAtlasTextBlob;
class GrAtlasTextStrike;
class GrClip;
+class GrColorSpaceXform;
class GrContext;
class GrPaint;
class GrRenderTargetContext;
class GrShaderCaps;
+class SkColorSpace;
class SkDrawFilter;
class SkGlyph;
class SkMatrix;
@@ -45,12 +47,19 @@
*/
class Paint {
public:
- explicit Paint(const SkPaint* paint) : fPaint(paint) { this->initFilteredColor(); }
+ explicit Paint(const SkPaint* paint,
+ SkColorSpace* dstColorSpace,
+ GrColorSpaceXform* colorXformFromSRGB)
+ : fPaint(paint)
+ , fDstColorSpace(dstColorSpace)
+ , fColorXformFromSRGB(colorXformFromSRGB) {
+ this->initFilteredColor();
+ }
// These expose the paint's color run through its color filter (if any). This is only valid
// when drawing grayscale/lcd glyph masks and not when drawing color glyphs.
- SkColor filteredSkColor() const { return fFilteredSkColor; }
- GrColor filteredPremulGrColor() const { return fFilteredGrColor; }
+ GrColor filteredPremulColor() const { return fFilteredPremulColor; }
+ GrColor filteredUnpremulColor() const { return fFilteredUnpremulColor; }
const SkPaint& skPaint() const { return *fPaint; }
operator const SkPaint&() const { return this->skPaint(); }
@@ -58,21 +67,21 @@
bool toGrPaint(GrMaskFormat, GrRenderTargetContext*, const SkMatrix& viewMatrix,
GrPaint*) const;
+ // Just for RunPaint's constructor
+ SkColorSpace* dstColorSpace() const { return fDstColorSpace; }
+ GrColorSpaceXform* colorXformFromSRGB() const { return fColorXformFromSRGB; }
+
protected:
- void initFilteredColor() {
- fFilteredSkColor = fPaint->getColor();
- if (fPaint->getColorFilter()) {
- fFilteredSkColor = fPaint->getColorFilter()->filterColor(fFilteredSkColor);
- }
- fFilteredGrColor = SkColorToPremulGrColor(fFilteredSkColor);
- }
+ void initFilteredColor();
Paint() = default;
const SkPaint* fPaint;
+ SkColorSpace* fDstColorSpace;
+ GrColorSpaceXform* fColorXformFromSRGB;
// This is the paint's color run through its color filter, if present. This color should
// be used except when rendering bitmap text, in which case the bitmap must be filtered in
// the fragment shader.
- SkColor fFilteredSkColor;
- SkColor fFilteredGrColor;
+ GrColor fFilteredUnpremulColor;
+ GrColor fFilteredPremulColor;
};
/**
@@ -86,8 +95,10 @@
: fOriginalPaint(paint), fFilter(filter), fProps(props) {
// Initially we represent the original paint.
fPaint = &fOriginalPaint->skPaint();
- fFilteredSkColor = fOriginalPaint->filteredSkColor();
- fFilteredGrColor = fOriginalPaint->filteredPremulGrColor();
+ fDstColorSpace = fOriginalPaint->dstColorSpace();
+ fColorXformFromSRGB = fOriginalPaint->colorXformFromSRGB();
+ fFilteredPremulColor = fOriginalPaint->filteredPremulColor();
+ fFilteredUnpremulColor = fOriginalPaint->filteredUnpremulColor();
}
bool modifyForRun(const SkTextBlobRunIterator&);