Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(555)

Side by Side Diff: src/gpu/GrDistanceFieldTextContext.cpp

Issue 1042373002: Emulate gamma fix by making glyphs thicker or thinner (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Some clean up Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/gpu/GrDistanceFieldTextContext.h ('k') | src/gpu/effects/GrDistanceFieldTextureEffect.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2013 Google Inc. 2 * Copyright 2013 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "GrDistanceFieldTextContext.h" 8 #include "GrDistanceFieldTextContext.h"
9 #include "GrAtlas.h" 9 #include "GrAtlas.h"
10 #include "GrBitmapTextContext.h" 10 #include "GrBitmapTextContext.h"
(...skipping 24 matching lines...) Expand all
35 static const int kMinDFFontSize = 18; 35 static const int kMinDFFontSize = 18;
36 static const int kSmallDFFontSize = 32; 36 static const int kSmallDFFontSize = 32;
37 static const int kSmallDFFontLimit = 32; 37 static const int kSmallDFFontLimit = 32;
38 static const int kMediumDFFontSize = 72; 38 static const int kMediumDFFontSize = 72;
39 static const int kMediumDFFontLimit = 72; 39 static const int kMediumDFFontLimit = 72;
40 static const int kLargeDFFontSize = 162; 40 static const int kLargeDFFontSize = 162;
41 41
42 static const int kVerticesPerGlyph = 4; 42 static const int kVerticesPerGlyph = 4;
43 static const int kIndicesPerGlyph = 6; 43 static const int kIndicesPerGlyph = 6;
44 44
45 #ifdef SK_DEBUG
46 static const int kExpectedDistanceAdjustTableSize = 8;
47 #endif
48 static const int kDistanceAdjustLumShift = 5;
49
45 GrDistanceFieldTextContext::GrDistanceFieldTextContext(GrContext* context, 50 GrDistanceFieldTextContext::GrDistanceFieldTextContext(GrContext* context,
46 SkGpuDevice* gpuDevice, 51 SkGpuDevice* gpuDevice,
47 const SkDeviceProperties& properties, 52 const SkDeviceProperties& properties,
48 bool enable) 53 bool enable)
49 : GrTextContext(context, gpuDevice, properties) { 54 : GrTextContext(context, gpuDevice, properties) {
50 #if SK_FORCE_DISTANCE_FIELD_TEXT 55 #if SK_FORCE_DISTANCE_FIELD_TEXT
51 fEnableDFRendering = true; 56 fEnableDFRendering = true;
52 #else 57 #else
53 fEnableDFRendering = enable; 58 fEnableDFRendering = enable;
54 #endif 59 #endif
55 fStrike = NULL; 60 fStrike = NULL;
56 fGammaTexture = NULL; 61 fDistanceAdjustTable = NULL;
57 62
58 fEffectTextureUniqueID = SK_InvalidUniqueID; 63 fEffectTextureUniqueID = SK_InvalidUniqueID;
59 fEffectColor = GrColor_ILLEGAL; 64 fEffectColor = GrColor_ILLEGAL;
60 fEffectFlags = kInvalid_DistanceFieldEffectFlag; 65 fEffectFlags = kInvalid_DistanceFieldEffectFlag;
61 66
62 fVertices = NULL; 67 fVertices = NULL;
63 fCurrVertex = 0; 68 fCurrVertex = 0;
64 fAllocVertexCount = 0; 69 fAllocVertexCount = 0;
65 fTotalVertexCount = 0; 70 fTotalVertexCount = 0;
66 fCurrTexture = NULL; 71 fCurrTexture = NULL;
67 72
68 fVertexBounds.setLargestInverted(); 73 fVertexBounds.setLargestInverted();
69 } 74 }
70 75
71 GrDistanceFieldTextContext* GrDistanceFieldTextContext::Create(GrContext* contex t, 76 GrDistanceFieldTextContext* GrDistanceFieldTextContext::Create(GrContext* contex t,
72 SkGpuDevice* gpuD evice, 77 SkGpuDevice* gpuD evice,
73 const SkDevicePro perties& props, 78 const SkDevicePro perties& props,
74 bool enable) { 79 bool enable) {
75 GrDistanceFieldTextContext* textContext = SkNEW_ARGS(GrDistanceFieldTextCont ext, 80 GrDistanceFieldTextContext* textContext = SkNEW_ARGS(GrDistanceFieldTextCont ext,
76 (context, gpuDevice, pr ops, enable)); 81 (context, gpuDevice, pr ops, enable));
82 textContext->buildDistanceAdjustTable();
77 #ifdef USE_BITMAP_TEXTBLOBS 83 #ifdef USE_BITMAP_TEXTBLOBS
78 textContext->fFallbackTextContext = GrBitmapTextContextB::Create(context, gp uDevice, props); 84 textContext->fFallbackTextContext = GrBitmapTextContextB::Create(context, gp uDevice, props);
79 #else 85 #else
80 textContext->fFallbackTextContext = GrBitmapTextContext::Create(context, gpu Device, props); 86 textContext->fFallbackTextContext = GrBitmapTextContext::Create(context, gpu Device, props);
81 #endif 87 #endif
82 88
83 return textContext; 89 return textContext;
84 } 90 }
85 91
92 void GrDistanceFieldTextContext::buildDistanceAdjustTable() {
93
94 // This is used for an approximation of the mask gamma hack, used by raster and bitmap
95 // text. The mask gamma hack is based off of guessing what the blend color i s going to
96 // be, and adjusting the mask so that when run through the linear blend will
97 // produce the value closest to the desired result. However, in practice thi s means
98 // that the 'adjusted' mask is just increasing or decreasing the coverage of
99 // the mask depending on what it is thought it will blit against. For black (on
100 // assumed white) this means that coverages are decreased (on a curve). For white (on
101 // assumed black) this means that coverages are increased (on a a curve). At
102 // middle (perceptual) gray (which could be blit against anything) the cover ages
103 // remain the same.
104 //
105 // The idea here is that instead of determining the initial (real) coverage and
106 // then adjusting that coverage, we determine an adjusted coverage directly by
107 // essentially manipulating the geometry (in this case, the distance to the glyph
108 // edge). So for black (on assumed white) this thins a bit; for white (on
109 // assumed black) this fake bolds the geometry a bit.
110 //
111 // The distance adjustment is calculated by determining the actual coverage value which
112 // when fed into in the mask gamma table gives us an 'adjusted coverage' val ue of 0.5. This
113 // actual coverage value (assuming it's between 0 and 1) corresponds to a di stance from the
114 // actual edge. So by subtracting this distance adjustment and computing wit hout the
115 // the coverage adjustment we should get 0.5 coverage at the same point.
116 //
117 // This has several implications:
118 // For non-gray lcd smoothed text, each subpixel essentially is using a
119 // slightly different geometry.
120 //
121 // For black (on assumed white) this may not cover some pixels which wer e
122 // previously covered; however those pixels would have been only slightl y
123 // covered and that slight coverage would have been decreased anyway. Al so, some pixels
124 // which were previously fully covered may no longer be fully covered.
125 //
126 // For white (on assumed black) this may cover some pixels which weren't
127 // previously covered at all.
128
129 int width, height;
130 size_t size;
131
132 #ifdef SK_GAMMA_CONTRAST
133 SkScalar contrast = SK_GAMMA_CONTRAST;
134 #else
135 SkScalar contrast = 0.5f;
136 #endif
137 SkScalar paintGamma = fDeviceProperties.gamma();
138 SkScalar deviceGamma = fDeviceProperties.gamma();
139
140 size = SkScalerContext::GetGammaLUTSize(contrast, paintGamma, deviceGamma,
141 &width, &height);
142
143 SkASSERT(kExpectedDistanceAdjustTableSize == height);
144 fDistanceAdjustTable = SkNEW_ARRAY(SkScalar, height);
145
146 SkAutoTArray<uint8_t> data((int)size);
147 SkScalerContext::GetGammaLUTData(contrast, paintGamma, deviceGamma, data.get ());
148
149 // find the inverse points where we cross 0.5
150 // binsearch might be better, but we only need to do this once on creation
151 for (int row = 0; row < height; ++row) {
152 uint8_t* rowPtr = data.get() + row*width;
153 for (int col = 0; col < width - 1; ++col) {
154 if (rowPtr[col] <= 127 && rowPtr[col + 1] >= 128) {
155 // compute point where a mask value will give us a result of 0.5
156 float interp = (127.5f - rowPtr[col]) / (rowPtr[col + 1] - rowPt r[col]);
157 float borderAlpha = (col + interp) / 255.f;
158
159 // compute t value for that alpha
160 // this is an approximate inverse for smoothstep()
161 float t = borderAlpha*(borderAlpha*(4.0f*borderAlpha - 6.0f) + 5 .0f) / 3.0f;
162
163 // compute distance which gives us that t value
164 const float kDistanceFieldAAFactor = 0.65f; // should match SK_D istanceFieldAAFactor
165 float d = 2.0f*kDistanceFieldAAFactor*t - kDistanceFieldAAFactor ;
166
167 fDistanceAdjustTable[row] = d;
168 break;
169 }
170 }
171 }
172 }
173
174
86 GrDistanceFieldTextContext::~GrDistanceFieldTextContext() { 175 GrDistanceFieldTextContext::~GrDistanceFieldTextContext() {
87 SkSafeSetNull(fGammaTexture); 176 SkDELETE_ARRAY(fDistanceAdjustTable);
177 fDistanceAdjustTable = NULL;
88 } 178 }
89 179
90 bool GrDistanceFieldTextContext::canDraw(const GrRenderTarget* rt, 180 bool GrDistanceFieldTextContext::canDraw(const GrRenderTarget* rt,
91 const GrClip& clip, 181 const GrClip& clip,
92 const GrPaint& paint, 182 const GrPaint& paint,
93 const SkPaint& skPaint, 183 const SkPaint& skPaint,
94 const SkMatrix& viewMatrix) { 184 const SkMatrix& viewMatrix) {
95 // TODO: support perspective (need getMaxScale replacement) 185 // TODO: support perspective (need getMaxScale replacement)
96 if (viewMatrix.hasPerspective()) { 186 if (viewMatrix.hasPerspective()) {
97 return false; 187 return false;
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
175 } 265 }
176 266
177 fUseLCDText = fSkPaint.isLCDRenderText(); 267 fUseLCDText = fSkPaint.isLCDRenderText();
178 268
179 fSkPaint.setLCDRenderText(false); 269 fSkPaint.setLCDRenderText(false);
180 fSkPaint.setAutohinted(false); 270 fSkPaint.setAutohinted(false);
181 fSkPaint.setHinting(SkPaint::kNormal_Hinting); 271 fSkPaint.setHinting(SkPaint::kNormal_Hinting);
182 fSkPaint.setSubpixelText(true); 272 fSkPaint.setSubpixelText(true);
183 } 273 }
184 274
185 static void setup_gamma_texture(GrContext* context, const SkGlyphCache* cache,
186 const SkDeviceProperties& deviceProperties,
187 GrTexture** gammaTexture) {
188 if (NULL == *gammaTexture) {
189 int width, height;
190 size_t size;
191
192 #ifdef SK_GAMMA_CONTRAST
193 SkScalar contrast = SK_GAMMA_CONTRAST;
194 #else
195 SkScalar contrast = 0.5f;
196 #endif
197 SkScalar paintGamma = deviceProperties.gamma();
198 SkScalar deviceGamma = deviceProperties.gamma();
199
200 size = SkScalerContext::GetGammaLUTSize(contrast, paintGamma, deviceGamm a,
201 &width, &height);
202
203 SkAutoTArray<uint8_t> data((int)size);
204 SkScalerContext::GetGammaLUTData(contrast, paintGamma, deviceGamma, data .get());
205
206 // TODO: Update this to use the cache rather than directly creating a te xture.
207 GrSurfaceDesc desc;
208 desc.fFlags = kNone_GrSurfaceFlags;
209 desc.fWidth = width;
210 desc.fHeight = height;
211 desc.fConfig = kAlpha_8_GrPixelConfig;
212
213 *gammaTexture = context->getGpu()->createTexture(desc, true, NULL, 0);
214 if (NULL == *gammaTexture) {
215 return;
216 }
217
218 (*gammaTexture)->writePixels(0, 0, width, height,
219 (*gammaTexture)->config(), data.get(), 0,
220 GrContext::kDontFlush_PixelOpsFlag);
221 }
222 }
223
224 void GrDistanceFieldTextContext::onDrawText(GrRenderTarget* rt, const GrClip& cl ip, 275 void GrDistanceFieldTextContext::onDrawText(GrRenderTarget* rt, const GrClip& cl ip,
225 const GrPaint& paint, 276 const GrPaint& paint,
226 const SkPaint& skPaint, const SkMatr ix& viewMatrix, 277 const SkPaint& skPaint, const SkMatr ix& viewMatrix,
227 const char text[], size_t byteLength , 278 const char text[], size_t byteLength ,
228 SkScalar x, SkScalar y, 279 SkScalar x, SkScalar y,
229 const SkIRect& regionClipBounds) { 280 const SkIRect& regionClipBounds) {
230 SkASSERT(byteLength == 0 || text != NULL); 281 SkASSERT(byteLength == 0 || text != NULL);
231 282
232 // nothing to draw 283 // nothing to draw
233 if (text == NULL || byteLength == 0) { 284 if (text == NULL || byteLength == 0) {
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
306 357
307 fViewMatrix = viewMatrix; 358 fViewMatrix = viewMatrix;
308 this->init(rt, clip, paint, skPaint, regionClipBounds); 359 this->init(rt, clip, paint, skPaint, regionClipBounds);
309 360
310 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); 361 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
311 362
312 SkAutoGlyphCacheNoGamma autoCache(fSkPaint, &fDeviceProperties, NULL); 363 SkAutoGlyphCacheNoGamma autoCache(fSkPaint, &fDeviceProperties, NULL);
313 SkGlyphCache* cache = autoCache.getCache(); 364 SkGlyphCache* cache = autoCache.getCache();
314 GrFontScaler* fontScaler = GetGrFontScaler(cache); 365 GrFontScaler* fontScaler = GetGrFontScaler(cache);
315 366
316 setup_gamma_texture(fContext, cache, fDeviceProperties, &fGammaTexture);
317
318 int numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL); 367 int numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL);
319 fTotalVertexCount = kVerticesPerGlyph*numGlyphs; 368 fTotalVertexCount = kVerticesPerGlyph*numGlyphs;
320 369
321 const char* stop = text + byteLength; 370 const char* stop = text + byteLength;
322 SkTArray<char> fallbackTxt; 371 SkTArray<char> fallbackTxt;
323 SkTArray<SkScalar> fallbackPos; 372 SkTArray<SkScalar> fallbackPos;
324 373
325 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) { 374 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
326 while (text < stop) { 375 while (text < stop) {
327 const char* lastText = text; 376 const char* lastText = text;
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
435 flags |= fUseLCDText && useBGR ? kBGR_DistanceFieldEffectFlag : 0; 484 flags |= fUseLCDText && useBGR ? kBGR_DistanceFieldEffectFlag : 0;
436 485
437 // see if we need to create a new effect 486 // see if we need to create a new effect
438 if (textureUniqueID != fEffectTextureUniqueID || 487 if (textureUniqueID != fEffectTextureUniqueID ||
439 filteredColor != fEffectColor || 488 filteredColor != fEffectColor ||
440 flags != fEffectFlags || 489 flags != fEffectFlags ||
441 !fCachedGeometryProcessor->viewMatrix().cheapEqualTo(fViewMatrix)) { 490 !fCachedGeometryProcessor->viewMatrix().cheapEqualTo(fViewMatrix)) {
442 GrColor color = fPaint.getColor(); 491 GrColor color = fPaint.getColor();
443 if (fUseLCDText) { 492 if (fUseLCDText) {
444 GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredCol or); 493 GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredCol or);
494
495 float redCorrection =
496 fDistanceAdjustTable[GrColorUnpackR(colorNoPreMul) >> kDistanceA djustLumShift];
497 float greenCorrection =
498 fDistanceAdjustTable[GrColorUnpackG(colorNoPreMul) >> kDistanceA djustLumShift];
499 float blueCorrection =
500 fDistanceAdjustTable[GrColorUnpackB(colorNoPreMul) >> kDistanceA djustLumShift];
501 GrDistanceFieldLCDTextureEffect::DistanceAdjust widthAdjust =
502 GrDistanceFieldLCDTextureEffect::DistanceAdjust::Make(redCorrect ion,
503 greenCorrecti on,
504 blueCorrectio n);
445 fCachedGeometryProcessor.reset(GrDistanceFieldLCDTextureEffect::Crea te(color, 505 fCachedGeometryProcessor.reset(GrDistanceFieldLCDTextureEffect::Crea te(color,
446 fViewMatrix, 506 fViewMatrix,
447 fCurrTexture, 507 fCurrTexture,
448 params, 508 params,
449 fGammaTexture, 509 widthAdjust,
450 gammaParams,
451 colorNoPreMul,
452 flags)); 510 flags));
453 } else { 511 } else {
454 flags |= kColorAttr_DistanceFieldEffectFlag; 512 flags |= kColorAttr_DistanceFieldEffectFlag;
455 bool opaque = GrColorIsOpaque(color); 513 bool opaque = GrColorIsOpaque(color);
456 #ifdef SK_GAMMA_APPLY_TO_A8 514 #ifdef SK_GAMMA_APPLY_TO_A8
457 U8CPU lum = SkColorSpaceLuminance::computeLuminance(fDevicePropertie s.gamma(), 515 U8CPU lum = SkColorSpaceLuminance::computeLuminance(fDevicePropertie s.gamma(),
458 filteredColor); 516 filteredColor);
517 float correction = fDistanceAdjustTable[lum >> kDistanceAdjustLumShi ft];
459 fCachedGeometryProcessor.reset(GrDistanceFieldTextureEffect::Create( color, 518 fCachedGeometryProcessor.reset(GrDistanceFieldTextureEffect::Create( color,
460 fViewMatrix, 519 fViewMatrix,
461 fCurrTexture, 520 fCurrTexture,
462 params, 521 params,
463 fGammaTexture, 522 correction,
464 gammaParams,
465 lum/255.f,
466 flags, 523 flags,
467 opaque)); 524 opaque));
468 #else 525 #else
469 fCachedGeometryProcessor.reset(GrDistanceFieldTextureEffect::Create( color, 526 fCachedGeometryProcessor.reset(GrDistanceFieldTextureEffect::Create( color,
470 fViewMatrix, 527 fViewMatrix,
471 fCurrTexture, 528 fCurrTexture,
472 params, 529 params,
473 flags, 530 flags,
474 opaque)); 531 opaque));
475 #endif 532 #endif
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after
736 } 793 }
737 } 794 }
738 795
739 inline void GrDistanceFieldTextContext::finish() { 796 inline void GrDistanceFieldTextContext::finish() {
740 this->flush(); 797 this->flush();
741 fTotalVertexCount = 0; 798 fTotalVertexCount = 0;
742 799
743 GrTextContext::finish(); 800 GrTextContext::finish();
744 } 801 }
745 802
OLDNEW
« no previous file with comments | « src/gpu/GrDistanceFieldTextContext.h ('k') | src/gpu/effects/GrDistanceFieldTextureEffect.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698