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:
parent
07072944af
commit
ec8f8b0643
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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()) {
|
||||
|
@ -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);
|
||||
|
@ -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&);
|
||||
|
Loading…
Reference in New Issue
Block a user