// 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) {
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,
} 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,
static GrAtlasTextBatch* CreateDistanceField(
int glyphCount, GrBatchFontCache* fontCache,
const GrDistanceFieldAdjustTable* distanceAdjustTable,
+ bool useSRGBDistanceTable,
SkColor filteredColor, bool isLCD,
bool useBGR) {
GrAtlasTextBatch* batch = new GrAtlasTextBatch;
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;
// Distance field properties
SkAutoTUnref<const GrDistanceFieldAdjustTable> fDistanceAdjustTable;
SkColor fFilteredColor;
+ bool fUseSRGBDistanceTable;
friend class GrBlobRegenHelper; // Needs to trigger flushes
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);
// 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);
}
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);
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);");
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)
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,
};
/**
GrColor color,
const SkPaint& skPaint, const SkSurfaceProps& props,
const GrDistanceFieldAdjustTable* distanceAdjustTable,
+ bool useSRGBDistanceTable,
GrBatchFontCache* cache) {
GrMaskFormat format = info.maskFormat();
GrColor subRunColor;
}
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);
}
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);
}
}
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) {
GrColor color,
const SkPaint& skPaint, const SkSurfaceProps& props,
const GrDistanceFieldAdjustTable* distanceAdjustTable,
+ bool useSRGBDistanceTable,
GrBatchFontCache* cache);
struct BigGlyph {
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
#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());
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);
}
// 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