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>
This commit is contained in:
Brian Osman 2017-05-11 10:57:37 -04:00 committed by Skia Commit-Bot
parent 07072944af
commit ec8f8b0643
8 changed files with 79 additions and 45 deletions

View File

@ -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 @@ bool GrAtlasTextOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
// 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 @@ sk_sp<GrGeometryProcessor> GrAtlasTextOp::setupDfProcessor(GrResourceProvider* r
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 @@ sk_sp<GrGeometryProcessor> GrAtlasTextOp::setupDfProcessor(GrResourceProvider* r
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,

View File

@ -64,7 +64,7 @@ public:
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 @@ private:
// 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 @@ private:
// Distance field properties
sk_sp<const GrDistanceFieldAdjustTable> fDistanceAdjustTable;
SkColor fFilteredColor;
GrColor fFilteredColor;
bool fUseGammaCorrectDistanceTable;
friend class GrBlobRegenHelper; // Needs to trigger flushes

View File

@ -179,7 +179,7 @@ bool GrAtlasTextBlob::mustRegenerate(const GrTextUtils::Paint& paint,
// 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 @@ inline std::unique_ptr<GrLegacyMeshDrawOp> GrAtlasTextBlob::makeOp(
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 @@ inline std::unique_ptr<GrLegacyMeshDrawOp> GrAtlasTextBlob::makeOp(
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();

View File

@ -240,7 +240,7 @@ public:
// 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 @@ private:
SkMatrix fInitialViewMatrix;
SkMatrix fInitialViewMatrixInverse;
size_t fSize;
SkColor fFilteredPaintColor;
GrColor fFilteredPaintColor;
SkScalar fInitialX;
SkScalar fInitialY;

View File

@ -118,7 +118,7 @@ void GrAtlasTextContext::drawTextBlob(GrContext* context, GrRenderTargetContext*
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 @@ void GrAtlasTextContext::RegenerateTextBlob(GrAtlasTextBlob* cacheBlob,
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 @@ void GrAtlasTextContext::drawText(GrContext* context, GrRenderTargetContext* rtc
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 @@ void GrAtlasTextContext::drawPosText(GrContext* context, GrRenderTargetContext*
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 @@ DRAW_OP_TEST_DEFINE(TextBlobOp) {
}
// 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 @@ DRAW_OP_TEST_DEFINE(TextBlobOp) {
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(

View File

@ -134,7 +134,7 @@ void GrStencilAndCoverTextContext::uncachedDrawTextBlob(GrContext* context,
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()) {

View File

@ -50,6 +50,27 @@ bool GrTextUtils::Paint::toGrPaint(GrMaskFormat maskFormat, GrRenderTargetContex
}
}
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 @@ void GrTextUtils::DrawBmpText(GrAtlasTextBlob* blob, int runIndex, GrAtlasGlyphC
BmpAppendGlyph(
blob, runIndex, fontCache, &currStrike, glyph,
SkScalarFloorToInt(position.fX), SkScalarFloorToInt(position.fY),
paint.filteredPremulGrColor(), cache);
paint.filteredPremulColor(), cache);
}
);
@ -135,7 +156,7 @@ void GrTextUtils::DrawBmpPosText(GrAtlasTextBlob* blob, int runIndex, GrAtlasGly
BmpAppendGlyph(
blob, runIndex, fontCache, &currStrike, glyph,
SkScalarFloorToInt(position.fX), SkScalarFloorToInt(position.fY),
paint.filteredPremulGrColor(), cache);
paint.filteredPremulColor(), cache);
}
);
@ -390,7 +411,7 @@ void GrTextUtils::DrawDFPosText(GrAtlasTextBlob* blob, int runIndex, GrAtlasGlyp
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 @@ void GrTextUtils::DrawDFPosText(GrAtlasTextBlob* blob, int runIndex, GrAtlasGlyp
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);

View File

@ -19,10 +19,12 @@ class GrAtlasGlyphCache;
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 @@ public:
*/
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 @@ public:
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 @@ public:
: 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&);