aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar brianosman <brianosman@google.com>2016-04-12 12:48:21 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-04-12 12:48:21 -0700
commit0586f5cc9713268238394411a5daa2c7758b092b (patch)
tree74d7c1a3786a306dab0dd3fdfe8e1bcb25f9f57f
parent134ff5c9cf99e1a930cb1b77bf8fb2b7b2c31d31 (diff)
sRGB support for distance field text.
Add a second distance field adjust table that only applies contrast, not fake-gamma correction. Store a flag in the batch at creation time, using the same logic we apply elsewhere (render target format, plus paint flags). That gets us close, but not as good as bitmap text. The final step is to use a linear step function (rather than smoothstep) to map distance to coverage, when we have sRGB output. Smoothstep's nonlinear response is actually doing some fake-gamma, so it ends up over-correcting when the output is already gamma-correct. Results are now very close between L32 (old table, smoothstep) and S32 (contrast-only table, linstep). BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1885613002 Review URL: https://codereview.chromium.org/1885613002
-rw-r--r--src/gpu/batches/GrAtlasTextBatch.cpp16
-rw-r--r--src/gpu/batches/GrAtlasTextBatch.h3
-rw-r--r--src/gpu/effects/GrDistanceFieldGeoProc.cpp26
-rw-r--r--src/gpu/effects/GrDistanceFieldGeoProc.h7
-rw-r--r--src/gpu/text/GrAtlasTextBlob.cpp13
-rw-r--r--src/gpu/text/GrAtlasTextBlob.h1
-rw-r--r--src/gpu/text/GrDistanceFieldAdjustTable.cpp15
-rw-r--r--src/gpu/text/GrDistanceFieldAdjustTable.h14
8 files changed, 69 insertions, 26 deletions
diff --git a/src/gpu/batches/GrAtlasTextBatch.cpp b/src/gpu/batches/GrAtlasTextBatch.cpp
index ca6b99ea33..03b3ad0363 100644
--- a/src/gpu/batches/GrAtlasTextBatch.cpp
+++ b/src/gpu/batches/GrAtlasTextBatch.cpp
@@ -261,6 +261,7 @@ GrGeometryProcessor* GrAtlasTextBatch::setupDfProcessor(const SkMatrix& viewMatr
// set up any flags
uint32_t flags = viewMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
flags |= viewMatrix.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0;
+ flags |= fUseSRGBDistanceTable ? kSRGB_DistanceFieldEffectFlag : 0;
// see if we need to create a new effect
if (isLCD) {
@@ -269,12 +270,12 @@ GrGeometryProcessor* GrAtlasTextBatch::setupDfProcessor(const SkMatrix& viewMatr
GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor);
- float redCorrection =
- (*fDistanceAdjustTable)[GrColorUnpackR(colorNoPreMul) >> kDistanceAdjustLumShift];
- float greenCorrection =
- (*fDistanceAdjustTable)[GrColorUnpackG(colorNoPreMul) >> kDistanceAdjustLumShift];
- float blueCorrection =
- (*fDistanceAdjustTable)[GrColorUnpackB(colorNoPreMul) >> kDistanceAdjustLumShift];
+ float redCorrection = fDistanceAdjustTable->getAdjustment(
+ GrColorUnpackR(colorNoPreMul) >> kDistanceAdjustLumShift, fUseSRGBDistanceTable);
+ float greenCorrection = fDistanceAdjustTable->getAdjustment(
+ GrColorUnpackG(colorNoPreMul) >> kDistanceAdjustLumShift, fUseSRGBDistanceTable);
+ float blueCorrection = fDistanceAdjustTable->getAdjustment(
+ GrColorUnpackB(colorNoPreMul) >> kDistanceAdjustLumShift, fUseSRGBDistanceTable);
GrDistanceFieldLCDTextGeoProc::DistanceAdjust widthAdjust =
GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(redCorrection,
greenCorrection,
@@ -290,7 +291,8 @@ GrGeometryProcessor* GrAtlasTextBatch::setupDfProcessor(const SkMatrix& viewMatr
} else {
#ifdef SK_GAMMA_APPLY_TO_A8
U8CPU lum = SkColorSpaceLuminance::computeLuminance(SK_GAMMA_EXPONENT, filteredColor);
- float correction = (*fDistanceAdjustTable)[lum >> kDistanceAdjustLumShift];
+ float correction = fDistanceAdjustTable->getAdjustment(
+ lum >> kDistanceAdjustLumShift, fUseSRGBDistanceTable);
return GrDistanceFieldA8TextGeoProc::Create(color,
viewMatrix,
texture,
diff --git a/src/gpu/batches/GrAtlasTextBatch.h b/src/gpu/batches/GrAtlasTextBatch.h
index e883fa1d9f..629027a003 100644
--- a/src/gpu/batches/GrAtlasTextBatch.h
+++ b/src/gpu/batches/GrAtlasTextBatch.h
@@ -58,6 +58,7 @@ public:
static GrAtlasTextBatch* CreateDistanceField(
int glyphCount, GrBatchFontCache* fontCache,
const GrDistanceFieldAdjustTable* distanceAdjustTable,
+ bool useSRGBDistanceTable,
SkColor filteredColor, bool isLCD,
bool useBGR) {
GrAtlasTextBatch* batch = new GrAtlasTextBatch;
@@ -65,6 +66,7 @@ public:
batch->fFontCache = fontCache;
batch->fMaskType = isLCD ? kLCDDistanceField_MaskType : kGrayscaleDistanceField_MaskType;
batch->fDistanceAdjustTable.reset(SkRef(distanceAdjustTable));
+ batch->fUseSRGBDistanceTable = useSRGBDistanceTable;
batch->fFilteredColor = filteredColor;
batch->fUseBGR = useBGR;
batch->fBatch.fNumGlyphs = glyphCount;
@@ -182,6 +184,7 @@ private:
// Distance field properties
SkAutoTUnref<const GrDistanceFieldAdjustTable> fDistanceAdjustTable;
SkColor fFilteredColor;
+ bool fUseSRGBDistanceTable;
friend class GrBlobRegenHelper; // Needs to trigger flushes
diff --git a/src/gpu/effects/GrDistanceFieldGeoProc.cpp b/src/gpu/effects/GrDistanceFieldGeoProc.cpp
index 0c4125d962..e754661065 100644
--- a/src/gpu/effects/GrDistanceFieldGeoProc.cpp
+++ b/src/gpu/effects/GrDistanceFieldGeoProc.cpp
@@ -82,6 +82,7 @@ public:
bool isUniformScale = (dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask) ==
kUniformScale_DistanceFieldEffectMask;
bool isSimilarity = SkToBool(dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag);
+ bool srgbOutput = SkToBool(dfTexEffect.getFlags() & kSRGB_DistanceFieldEffectFlag);
varyingHandler->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision);
vertBuilder->codeAppendf("%s = %s;", uv.vsOut(), dfTexEffect.inTextureCoords()->fName);
@@ -153,7 +154,16 @@ public:
// this gives us a smooth step across approximately one fragment
fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
}
- fragBuilder->codeAppend("float val = smoothstep(-afwidth, afwidth, distance);");
+
+ // The smoothstep falloff compensates for the non-linear sRGB response curve. If we are
+ // doing gamma-correct rendering (to an sRGB or F16 buffer), then we actually want distance
+ // mapped linearly to coverage, so use a linear step:
+ if (srgbOutput) {
+ fragBuilder->codeAppend(
+ "float val = clamp(distance + afwidth / (2.0 * afwidth), 0.0, 1.0);");
+ } else {
+ fragBuilder->codeAppend("float val = smoothstep(-afwidth, afwidth, distance);");
+ }
fragBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage);
}
@@ -553,6 +563,7 @@ public:
bool isUniformScale = (dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask) ==
kUniformScale_DistanceFieldEffectMask;
bool isSimilarity = SkToBool(dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag);
+ bool srgbOutput = SkToBool(dfTexEffect.getFlags() & kSRGB_DistanceFieldEffectFlag);
GrGLSLVertToFrag recipScale(kFloat_GrSLType);
GrGLSLVertToFrag uv(kVec2f_GrSLType);
varyingHandler->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision);
@@ -667,8 +678,17 @@ public:
fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
}
- fragBuilder->codeAppend(
- "vec4 val = vec4(smoothstep(vec3(-afwidth), vec3(afwidth), distance), 1.0);");
+ // The smoothstep falloff compensates for the non-linear sRGB response curve. If we are
+ // doing gamma-correct rendering (to an sRGB or F16 buffer), then we actually want distance
+ // mapped linearly to coverage, so use a linear step:
+ if (srgbOutput) {
+ fragBuilder->codeAppend("vec4 val = "
+ "vec4(clamp(distance + vec3(afwidth) / vec3(2.0 * afwidth), 0.0, 1.0), 1.0f);");
+ } else {
+ fragBuilder->codeAppend(
+ "vec4 val = vec4(smoothstep(vec3(-afwidth), vec3(afwidth), distance), 1.0);");
+ }
+
// set alpha to be max of rgb coverage
fragBuilder->codeAppend("val.a = max(max(val.r, val.g), val.b);");
diff --git a/src/gpu/effects/GrDistanceFieldGeoProc.h b/src/gpu/effects/GrDistanceFieldGeoProc.h
index 05fffa58d6..2786b7e823 100644
--- a/src/gpu/effects/GrDistanceFieldGeoProc.h
+++ b/src/gpu/effects/GrDistanceFieldGeoProc.h
@@ -22,6 +22,7 @@ enum GrDistanceFieldEffectFlags {
kUseLCD_DistanceFieldEffectFlag = 0x04, // use lcd text
kBGR_DistanceFieldEffectFlag = 0x08, // lcd display has bgr order
kPortrait_DistanceFieldEffectFlag = 0x10, // lcd display is in portrait mode (not used yet)
+ kSRGB_DistanceFieldEffectFlag = 0x20, // assume sRGB dest (use linstep, not smoothstep)
kInvalid_DistanceFieldEffectFlag = 0x80, // invalid state (for initialization)
@@ -29,12 +30,14 @@ enum GrDistanceFieldEffectFlags {
kScaleOnly_DistanceFieldEffectFlag,
// The subset of the flags relevant to GrDistanceFieldA8TextGeoProc
kNonLCD_DistanceFieldEffectMask = kSimilarity_DistanceFieldEffectFlag |
- kScaleOnly_DistanceFieldEffectFlag,
+ kScaleOnly_DistanceFieldEffectFlag |
+ kSRGB_DistanceFieldEffectFlag,
// The subset of the flags relevant to GrDistanceFieldLCDTextGeoProc
kLCD_DistanceFieldEffectMask = kSimilarity_DistanceFieldEffectFlag |
kScaleOnly_DistanceFieldEffectFlag |
kUseLCD_DistanceFieldEffectFlag |
- kBGR_DistanceFieldEffectFlag,
+ kBGR_DistanceFieldEffectFlag |
+ kSRGB_DistanceFieldEffectFlag,
};
/**
diff --git a/src/gpu/text/GrAtlasTextBlob.cpp b/src/gpu/text/GrAtlasTextBlob.cpp
index afbff46994..60f905df5f 100644
--- a/src/gpu/text/GrAtlasTextBlob.cpp
+++ b/src/gpu/text/GrAtlasTextBlob.cpp
@@ -257,6 +257,7 @@ inline GrDrawBatch* GrAtlasTextBlob::createBatch(
GrColor color,
const SkPaint& skPaint, const SkSurfaceProps& props,
const GrDistanceFieldAdjustTable* distanceAdjustTable,
+ bool useSRGBDistanceTable,
GrBatchFontCache* cache) {
GrMaskFormat format = info.maskFormat();
GrColor subRunColor;
@@ -278,8 +279,8 @@ inline GrDrawBatch* GrAtlasTextBlob::createBatch(
}
bool useBGR = SkPixelGeometryIsBGR(props.pixelGeometry());
batch = GrAtlasTextBatch::CreateDistanceField(glyphCount, cache,
- distanceAdjustTable, filteredColor,
- info.hasUseLCDText(), useBGR);
+ distanceAdjustTable, useSRGBDistanceTable,
+ filteredColor, info.hasUseLCDText(), useBGR);
} else {
batch = GrAtlasTextBatch::CreateBitmap(format, glyphCount, cache);
}
@@ -310,10 +311,14 @@ void GrAtlasTextBlob::flushRun(GrDrawContext* dc, GrPipelineBuilder* pipelineBui
continue;
}
+ bool useSRGBDistanceTable = GrPixelConfigIsSRGB(dc->accessRenderTarget()->config()) &&
+ !pipelineBuilder->getDisableOutputConversionToSRGB();
+
SkAutoTUnref<GrDrawBatch> batch(this->createBatch(info, glyphCount, run,
subRun, viewMatrix, x, y, color,
skPaint, props,
- distanceAdjustTable, cache));
+ distanceAdjustTable, useSRGBDistanceTable,
+ cache));
dc->drawBatch(pipelineBuilder, batch);
}
}
@@ -463,7 +468,7 @@ GrDrawBatch* GrAtlasTextBlob::test_createBatch(
GrBatchFontCache* cache) {
const GrAtlasTextBlob::Run::SubRunInfo& info = fRuns[run].fSubRunInfo[subRun];
return this->createBatch(info, glyphCount, run, subRun, viewMatrix, x, y, color, skPaint,
- props, distanceAdjustTable, cache);
+ props, distanceAdjustTable, false, cache);
}
void GrAtlasTextBlob::AssertEqual(const GrAtlasTextBlob& l, const GrAtlasTextBlob& r) {
diff --git a/src/gpu/text/GrAtlasTextBlob.h b/src/gpu/text/GrAtlasTextBlob.h
index bc1e0b4afc..9631ef1024 100644
--- a/src/gpu/text/GrAtlasTextBlob.h
+++ b/src/gpu/text/GrAtlasTextBlob.h
@@ -502,6 +502,7 @@ private:
GrColor color,
const SkPaint& skPaint, const SkSurfaceProps& props,
const GrDistanceFieldAdjustTable* distanceAdjustTable,
+ bool useSRGBDistanceTable,
GrBatchFontCache* cache);
struct BigGlyph {
diff --git a/src/gpu/text/GrDistanceFieldAdjustTable.cpp b/src/gpu/text/GrDistanceFieldAdjustTable.cpp
index 1c5aeceb80..c6da175e0b 100644
--- a/src/gpu/text/GrDistanceFieldAdjustTable.cpp
+++ b/src/gpu/text/GrDistanceFieldAdjustTable.cpp
@@ -11,7 +11,7 @@
SkDEBUGCODE(static const int kExpectedDistanceAdjustTableSize = 8;)
-void GrDistanceFieldAdjustTable::buildDistanceAdjustTable() {
+SkScalar* build_distance_adjust_table(SkScalar paintGamma, SkScalar deviceGamma) {
// This is used for an approximation of the mask gamma hack, used by raster and bitmap
// text. The mask gamma hack is based off of guessing what the blend color is going to
// be, and adjusting the mask so that when run through the linear blend will
@@ -55,14 +55,12 @@ void GrDistanceFieldAdjustTable::buildDistanceAdjustTable() {
#else
SkScalar contrast = 0.5f;
#endif
- SkScalar paintGamma = SK_GAMMA_EXPONENT;
- SkScalar deviceGamma = SK_GAMMA_EXPONENT;
size = SkScalerContext::GetGammaLUTSize(contrast, paintGamma, deviceGamma,
&width, &height);
SkASSERT(kExpectedDistanceAdjustTableSize == height);
- fTable = new SkScalar[height];
+ SkScalar* table = new SkScalar[height];
SkAutoTArray<uint8_t> data((int)size);
SkScalerContext::GetGammaLUTData(contrast, paintGamma, deviceGamma, data.get());
@@ -85,9 +83,16 @@ void GrDistanceFieldAdjustTable::buildDistanceAdjustTable() {
const float kDistanceFieldAAFactor = 0.65f; // should match SK_DistanceFieldAAFactor
float d = 2.0f*kDistanceFieldAAFactor*t - kDistanceFieldAAFactor;
- fTable[row] = d;
+ table[row] = d;
break;
}
}
}
+
+ return table;
+}
+
+void GrDistanceFieldAdjustTable::buildDistanceAdjustTables() {
+ fTable = build_distance_adjust_table(SK_GAMMA_EXPONENT, SK_GAMMA_EXPONENT);
+ fSRGBTable = build_distance_adjust_table(SK_Scalar1, SK_Scalar1);
}
diff --git a/src/gpu/text/GrDistanceFieldAdjustTable.h b/src/gpu/text/GrDistanceFieldAdjustTable.h
index f7d8bee089..f9b5161e95 100644
--- a/src/gpu/text/GrDistanceFieldAdjustTable.h
+++ b/src/gpu/text/GrDistanceFieldAdjustTable.h
@@ -15,17 +15,21 @@
// Because the GrAtlasTextContext can go out of scope before the final flush, this needs to be
// refcnted and malloced
struct GrDistanceFieldAdjustTable : public SkNVRefCnt<GrDistanceFieldAdjustTable> {
- GrDistanceFieldAdjustTable() { this->buildDistanceAdjustTable(); }
- ~GrDistanceFieldAdjustTable() { delete[] fTable; }
+ GrDistanceFieldAdjustTable() { this->buildDistanceAdjustTables(); }
+ ~GrDistanceFieldAdjustTable() {
+ delete[] fTable;
+ delete[] fSRGBTable;
+ }
- const SkScalar& operator[] (int i) const {
- return fTable[i];
+ const SkScalar& getAdjustment(int i, bool useSRGBTable) const {
+ return useSRGBTable ? fSRGBTable[i] : fTable[i];
}
private:
- void buildDistanceAdjustTable();
+ void buildDistanceAdjustTables();
SkScalar* fTable;
+ SkScalar* fSRGBTable;
};
#endif