| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2010 Google Inc. | 2 * Copyright 2010 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 | 8 |
| 9 | |
| 10 #include "GrTextContext.h" | 9 #include "GrTextContext.h" |
| 11 #include "GrAtlas.h" | |
| 12 #include "GrContext.h" | |
| 13 #include "GrDrawTarget.h" | |
| 14 #include "GrFontScaler.h" | |
| 15 #include "GrIndexBuffer.h" | |
| 16 #include "GrTextStrike.h" | |
| 17 #include "GrTextStrike_impl.h" | |
| 18 #include "SkPath.h" | |
| 19 #include "SkRTConf.h" | |
| 20 #include "SkStrokeRec.h" | |
| 21 #include "effects/GrCustomCoordsTextureEffect.h" | |
| 22 | |
| 23 static const int kGlyphCoordsAttributeIndex = 1; | |
| 24 | |
| 25 SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false, | |
| 26 "Dump the contents of the font cache before every purge."); | |
| 27 | |
| 28 void GrTextContext::flushGlyphs() { | |
| 29 if (NULL == fDrawTarget) { | |
| 30 return; | |
| 31 } | |
| 32 | |
| 33 GrDrawState* drawState = fDrawTarget->drawState(); | |
| 34 GrDrawState::AutoRestoreEffects are(drawState); | |
| 35 drawState->setFromPaint(fPaint, SkMatrix::I(), fContext->getRenderTarget()); | |
| 36 | |
| 37 if (fCurrVertex > 0) { | |
| 38 // setup our sampler state for our text texture/atlas | |
| 39 SkASSERT(GrIsALIGN4(fCurrVertex)); | |
| 40 SkASSERT(fCurrTexture); | |
| 41 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kNon
e_FilterMode); | |
| 42 | |
| 43 // This effect could be stored with one of the cache objects (atlas?) | |
| 44 drawState->addCoverageEffect( | |
| 45 GrCustomCoordsTextureEffect::Create(fCurrTexture
, params), | |
| 46 kGlyphCoordsAttributeIndex)->unref(); | |
| 47 | |
| 48 if (!GrPixelConfigIsAlphaOnly(fCurrTexture->config())) { | |
| 49 if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() || | |
| 50 kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() || | |
| 51 fPaint.numColorStages()) { | |
| 52 GrPrintf("LCD Text will not draw correctly.\n"); | |
| 53 } | |
| 54 // setup blend so that we get mask * paintColor + (1-mask)*dstColor | |
| 55 drawState->setBlendConstant(fPaint.getColor()); | |
| 56 drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff); | |
| 57 // don't modulate by the paint's color in the frag since we're | |
| 58 // already doing it via the blend const. | |
| 59 drawState->setColor(0xffffffff); | |
| 60 } else { | |
| 61 // set back to normal in case we took LCD path previously. | |
| 62 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlen
dCoeff()); | |
| 63 drawState->setColor(fPaint.getColor()); | |
| 64 } | |
| 65 | |
| 66 int nGlyphs = fCurrVertex / 4; | |
| 67 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer()); | |
| 68 fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType, | |
| 69 nGlyphs, | |
| 70 4, 6); | |
| 71 fDrawTarget->resetVertexSource(); | |
| 72 fVertices = NULL; | |
| 73 fMaxVertices = 0; | |
| 74 fCurrVertex = 0; | |
| 75 SkSafeSetNull(fCurrTexture); | |
| 76 } | |
| 77 } | |
| 78 | 10 |
| 79 GrTextContext::GrTextContext(GrContext* context, const GrPaint& paint) : fPaint(
paint) { | 11 GrTextContext::GrTextContext(GrContext* context, const GrPaint& paint) : fPaint(
paint) { |
| 80 fContext = context; | 12 fContext = context; |
| 81 fStrike = NULL; | |
| 82 | |
| 83 fCurrTexture = NULL; | |
| 84 fCurrVertex = 0; | |
| 85 | 13 |
| 86 const GrClipData* clipData = context->getClip(); | 14 const GrClipData* clipData = context->getClip(); |
| 87 | 15 |
| 88 SkRect devConservativeBound; | 16 SkRect devConservativeBound; |
| 89 clipData->fClipStack->getConservativeBounds( | 17 clipData->fClipStack->getConservativeBounds( |
| 90 -clipData->fOrigin.fX, | 18 -clipData->fOrigin.fX, |
| 91 -clipData->fOrigin.fY, | 19 -clipData->fOrigin.fY, |
| 92 context->getRenderTarget()->width(), | 20 context->getRenderTarget()->width(), |
| 93 context->getRenderTarget()->height(), | 21 context->getRenderTarget()->height(), |
| 94 &devConservativeBound); | 22 &devConservativeBound); |
| 95 | 23 |
| 96 devConservativeBound.roundOut(&fClipRect); | 24 devConservativeBound.roundOut(&fClipRect); |
| 97 | 25 |
| 98 fAutoMatrix.setIdentity(fContext, &fPaint); | |
| 99 | |
| 100 fDrawTarget = fContext->getTextTarget(); | 26 fDrawTarget = fContext->getTextTarget(); |
| 101 | |
| 102 fVertices = NULL; | |
| 103 fMaxVertices = 0; | |
| 104 } | 27 } |
| 105 | 28 |
| 106 GrTextContext::~GrTextContext() { | |
| 107 this->flushGlyphs(); | |
| 108 } | |
| 109 | |
| 110 void GrTextContext::flush() { | |
| 111 this->flushGlyphs(); | |
| 112 } | |
| 113 | |
| 114 namespace { | |
| 115 | |
| 116 // position + texture coord | |
| 117 extern const GrVertexAttrib gTextVertexAttribs[] = { | |
| 118 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding
}, | |
| 119 {kVec2f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding} | |
| 120 }; | |
| 121 | |
| 122 }; | |
| 123 | |
| 124 void GrTextContext::drawPackedGlyph(GrGlyph::PackedID packed, | |
| 125 GrFixed vx, GrFixed vy, | |
| 126 GrFontScaler* scaler) { | |
| 127 if (NULL == fDrawTarget) { | |
| 128 return; | |
| 129 } | |
| 130 if (NULL == fStrike) { | |
| 131 fStrike = fContext->getFontCache()->getStrike(scaler); | |
| 132 } | |
| 133 | |
| 134 GrGlyph* glyph = fStrike->getGlyph(packed, scaler); | |
| 135 if (NULL == glyph || glyph->fBounds.isEmpty()) { | |
| 136 return; | |
| 137 } | |
| 138 | |
| 139 vx += SkIntToFixed(glyph->fBounds.fLeft); | |
| 140 vy += SkIntToFixed(glyph->fBounds.fTop); | |
| 141 | |
| 142 // keep them as ints until we've done the clip-test | |
| 143 GrFixed width = glyph->fBounds.width(); | |
| 144 GrFixed height = glyph->fBounds.height(); | |
| 145 | |
| 146 // check if we clipped out | |
| 147 if (true || NULL == glyph->fPlot) { | |
| 148 int x = vx >> 16; | |
| 149 int y = vy >> 16; | |
| 150 if (fClipRect.quickReject(x, y, x + width, y + height)) { | |
| 151 // SkCLZ(3); // so we can set a break-point in the debugger | |
| 152 return; | |
| 153 } | |
| 154 } | |
| 155 | |
| 156 if (NULL == glyph->fPlot) { | |
| 157 if (fStrike->getGlyphAtlas(glyph, scaler)) { | |
| 158 goto HAS_ATLAS; | |
| 159 } | |
| 160 | |
| 161 // try to clear out an unused plot before we flush | |
| 162 fContext->getFontCache()->freePlotExceptFor(fStrike); | |
| 163 if (fStrike->getGlyphAtlas(glyph, scaler)) { | |
| 164 goto HAS_ATLAS; | |
| 165 } | |
| 166 | |
| 167 if (c_DumpFontCache) { | |
| 168 #ifdef SK_DEVELOPER | |
| 169 fContext->getFontCache()->dump(); | |
| 170 #endif | |
| 171 } | |
| 172 | |
| 173 // before we purge the cache, we must flush any accumulated draws | |
| 174 this->flushGlyphs(); | |
| 175 fContext->flush(); | |
| 176 | |
| 177 // try to purge | |
| 178 fContext->getFontCache()->purgeExceptFor(fStrike); | |
| 179 // need to use new flush count here | |
| 180 if (fStrike->getGlyphAtlas(glyph, scaler)) { | |
| 181 goto HAS_ATLAS; | |
| 182 } | |
| 183 | |
| 184 if (NULL == glyph->fPath) { | |
| 185 SkPath* path = SkNEW(SkPath); | |
| 186 if (!scaler->getGlyphPath(glyph->glyphID(), path)) { | |
| 187 // flag the glyph as being dead? | |
| 188 delete path; | |
| 189 return; | |
| 190 } | |
| 191 glyph->fPath = path; | |
| 192 } | |
| 193 | |
| 194 GrContext::AutoMatrix am; | |
| 195 SkMatrix translate; | |
| 196 translate.setTranslate(SkFixedToScalar(vx - SkIntToFixed(glyph->fBounds.
fLeft)), | |
| 197 SkFixedToScalar(vy - SkIntToFixed(glyph->fBounds.
fTop))); | |
| 198 GrPaint tmpPaint(fPaint); | |
| 199 am.setPreConcat(fContext, translate, &tmpPaint); | |
| 200 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); | |
| 201 fContext->drawPath(tmpPaint, *glyph->fPath, stroke); | |
| 202 return; | |
| 203 } | |
| 204 | |
| 205 HAS_ATLAS: | |
| 206 SkASSERT(glyph->fPlot); | |
| 207 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken(); | |
| 208 glyph->fPlot->setDrawToken(drawToken); | |
| 209 | |
| 210 // now promote them to fixed (TODO: Rethink using fixed pt). | |
| 211 width = SkIntToFixed(width); | |
| 212 height = SkIntToFixed(height); | |
| 213 | |
| 214 GrTexture* texture = glyph->fPlot->texture(); | |
| 215 SkASSERT(texture); | |
| 216 | |
| 217 if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) { | |
| 218 this->flushGlyphs(); | |
| 219 fCurrTexture = texture; | |
| 220 fCurrTexture->ref(); | |
| 221 } | |
| 222 | |
| 223 if (NULL == fVertices) { | |
| 224 // If we need to reserve vertices allow the draw target to suggest | |
| 225 // a number of verts to reserve and whether to perform a flush. | |
| 226 fMaxVertices = kMinRequestedVerts; | |
| 227 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>( | |
| 228 SK_ARRAY_COUNT(gTextVertexAttribs)); | |
| 229 bool flush = fDrawTarget->geometryHints(&fMaxVertices, NULL); | |
| 230 if (flush) { | |
| 231 this->flushGlyphs(); | |
| 232 fContext->flush(); | |
| 233 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>( | |
| 234 SK_ARRAY_COUNT(gTextVertexAttribs)); | |
| 235 } | |
| 236 fMaxVertices = kDefaultRequestedVerts; | |
| 237 // ignore return, no point in flushing again. | |
| 238 fDrawTarget->geometryHints(&fMaxVertices, NULL); | |
| 239 | |
| 240 int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads(); | |
| 241 if (fMaxVertices < kMinRequestedVerts) { | |
| 242 fMaxVertices = kDefaultRequestedVerts; | |
| 243 } else if (fMaxVertices > maxQuadVertices) { | |
| 244 // don't exceed the limit of the index buffer | |
| 245 fMaxVertices = maxQuadVertices; | |
| 246 } | |
| 247 bool success = fDrawTarget->reserveVertexAndIndexSpace(fMaxVertices, | |
| 248 0, | |
| 249 GrTCast<void**>(&
fVertices), | |
| 250 NULL); | |
| 251 GrAlwaysAssert(success); | |
| 252 SkASSERT(2*sizeof(GrPoint) == fDrawTarget->getDrawState().getVertexSize(
)); | |
| 253 } | |
| 254 | |
| 255 GrFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX); | |
| 256 GrFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY); | |
| 257 | |
| 258 fVertices[2*fCurrVertex].setRectFan(SkFixedToFloat(vx), | |
| 259 SkFixedToFloat(vy), | |
| 260 SkFixedToFloat(vx + width), | |
| 261 SkFixedToFloat(vy + height), | |
| 262 2 * sizeof(SkPoint)); | |
| 263 fVertices[2*fCurrVertex+1].setRectFan(SkFixedToFloat(texture->normalizeFixed
X(tx)), | |
| 264 SkFixedToFloat(texture->normalizeFixed
Y(ty)), | |
| 265 SkFixedToFloat(texture->normalizeFixed
X(tx + width)), | |
| 266 SkFixedToFloat(texture->normalizeFixed
Y(ty + height)), | |
| 267 2 * sizeof(SkPoint)); | |
| 268 fCurrVertex += 4; | |
| 269 } | |
| OLD | NEW |