diff options
author | 2013-10-16 18:15:34 +0000 | |
---|---|---|
committer | 2013-10-16 18:15:34 +0000 | |
commit | c7a40fad0b4c243087ad1adb14ebc2184d42cac0 (patch) | |
tree | 0221bd972c7e7b7d7df8571762dee010f3c026b6 /src/gpu/GrBitmapTextContext.cpp | |
parent | 3f1f2a3a59c43e5bce67ab98e55df45bc7c933a3 (diff) |
Split out GrBitmapTextContext from GrTextContext.
This is a stepping stone to having a variety of different text context types
(bitmaps, distance fields, NV path rendering).
R=bsalomon@google.com
Review URL: https://codereview.chromium.org/27199002
git-svn-id: http://skia.googlecode.com/svn/trunk@11820 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/gpu/GrBitmapTextContext.cpp')
-rwxr-xr-x | src/gpu/GrBitmapTextContext.cpp | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/src/gpu/GrBitmapTextContext.cpp b/src/gpu/GrBitmapTextContext.cpp new file mode 100755 index 0000000000..7a99f093e5 --- /dev/null +++ b/src/gpu/GrBitmapTextContext.cpp @@ -0,0 +1,248 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrBitmapTextContext.h" +#include "GrAtlas.h" +#include "GrDrawTarget.h" +#include "GrFontScaler.h" +#include "GrIndexBuffer.h" +#include "GrTextStrike.h" +#include "GrTextStrike_impl.h" +#include "SkPath.h" +#include "SkRTConf.h" +#include "SkStrokeRec.h" +#include "effects/GrCustomCoordsTextureEffect.h" + +static const int kGlyphCoordsAttributeIndex = 1; + +SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false, + "Dump the contents of the font cache before every purge."); + +GrBitmapTextContext::GrBitmapTextContext(GrContext* context, const GrPaint& paint) : + GrTextContext(context, paint) { + fAutoMatrix.setIdentity(fContext, &fPaint); + + fStrike = NULL; + + fCurrTexture = NULL; + fCurrVertex = 0; + + fVertices = NULL; + fMaxVertices = 0; +} + +GrBitmapTextContext::~GrBitmapTextContext() { + this->flushGlyphs(); +} + +void GrBitmapTextContext::flushGlyphs() { + if (NULL == fDrawTarget) { + return; + } + + GrDrawState* drawState = fDrawTarget->drawState(); + GrDrawState::AutoRestoreEffects are(drawState); + drawState->setFromPaint(fPaint, SkMatrix::I(), fContext->getRenderTarget()); + + if (fCurrVertex > 0) { + // setup our sampler state for our text texture/atlas + SkASSERT(GrIsALIGN4(fCurrVertex)); + SkASSERT(fCurrTexture); + GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kNone_FilterMode); + + // This effect could be stored with one of the cache objects (atlas?) + drawState->addCoverageEffect( + GrCustomCoordsTextureEffect::Create(fCurrTexture, params), + kGlyphCoordsAttributeIndex)->unref(); + + if (!GrPixelConfigIsAlphaOnly(fCurrTexture->config())) { + if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() || + kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() || + fPaint.numColorStages()) { + GrPrintf("LCD Text will not draw correctly.\n"); + } + // setup blend so that we get mask * paintColor + (1-mask)*dstColor + drawState->setBlendConstant(fPaint.getColor()); + drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff); + // don't modulate by the paint's color in the frag since we're + // already doing it via the blend const. + drawState->setColor(0xffffffff); + } else { + // set back to normal in case we took LCD path previously. + drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff()); + drawState->setColor(fPaint.getColor()); + } + + int nGlyphs = fCurrVertex / 4; + fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer()); + fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType, + nGlyphs, + 4, 6); + fDrawTarget->resetVertexSource(); + fVertices = NULL; + fMaxVertices = 0; + fCurrVertex = 0; + SkSafeSetNull(fCurrTexture); + } +} + +namespace { + +// position + texture coord +extern const GrVertexAttrib gTextVertexAttribs[] = { + {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding}, + {kVec2f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding} +}; + +}; + +void GrBitmapTextContext::drawPackedGlyph(GrGlyph::PackedID packed, + GrFixed vx, GrFixed vy, + GrFontScaler* scaler) { + if (NULL == fDrawTarget) { + return; + } + if (NULL == fStrike) { + fStrike = fContext->getFontCache()->getStrike(scaler); + } + + GrGlyph* glyph = fStrike->getGlyph(packed, scaler); + if (NULL == glyph || glyph->fBounds.isEmpty()) { + return; + } + + vx += SkIntToFixed(glyph->fBounds.fLeft); + vy += SkIntToFixed(glyph->fBounds.fTop); + + // keep them as ints until we've done the clip-test + GrFixed width = glyph->fBounds.width(); + GrFixed height = glyph->fBounds.height(); + + // check if we clipped out + if (true || NULL == glyph->fPlot) { + int x = vx >> 16; + int y = vy >> 16; + if (fClipRect.quickReject(x, y, x + width, y + height)) { +// SkCLZ(3); // so we can set a break-point in the debugger + return; + } + } + + if (NULL == glyph->fPlot) { + if (fStrike->getGlyphAtlas(glyph, scaler)) { + goto HAS_ATLAS; + } + + // try to clear out an unused plot before we flush + fContext->getFontCache()->freePlotExceptFor(fStrike); + if (fStrike->getGlyphAtlas(glyph, scaler)) { + goto HAS_ATLAS; + } + + if (c_DumpFontCache) { +#ifdef SK_DEVELOPER + fContext->getFontCache()->dump(); +#endif + } + + // before we purge the cache, we must flush any accumulated draws + this->flushGlyphs(); + fContext->flush(); + + // try to purge + fContext->getFontCache()->purgeExceptFor(fStrike); + // need to use new flush count here + if (fStrike->getGlyphAtlas(glyph, scaler)) { + goto HAS_ATLAS; + } + + if (NULL == glyph->fPath) { + SkPath* path = SkNEW(SkPath); + if (!scaler->getGlyphPath(glyph->glyphID(), path)) { + // flag the glyph as being dead? + delete path; + return; + } + glyph->fPath = path; + } + + GrContext::AutoMatrix am; + SkMatrix translate; + translate.setTranslate(SkFixedToScalar(vx - SkIntToFixed(glyph->fBounds.fLeft)), + SkFixedToScalar(vy - SkIntToFixed(glyph->fBounds.fTop))); + GrPaint tmpPaint(fPaint); + am.setPreConcat(fContext, translate, &tmpPaint); + SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); + fContext->drawPath(tmpPaint, *glyph->fPath, stroke); + return; + } + +HAS_ATLAS: + SkASSERT(glyph->fPlot); + GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken(); + glyph->fPlot->setDrawToken(drawToken); + + // now promote them to fixed (TODO: Rethink using fixed pt). + width = SkIntToFixed(width); + height = SkIntToFixed(height); + + GrTexture* texture = glyph->fPlot->texture(); + SkASSERT(texture); + + if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) { + this->flushGlyphs(); + fCurrTexture = texture; + fCurrTexture->ref(); + } + + if (NULL == fVertices) { + // If we need to reserve vertices allow the draw target to suggest + // a number of verts to reserve and whether to perform a flush. + fMaxVertices = kMinRequestedVerts; + fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>( + SK_ARRAY_COUNT(gTextVertexAttribs)); + bool flush = fDrawTarget->geometryHints(&fMaxVertices, NULL); + if (flush) { + this->flushGlyphs(); + fContext->flush(); + fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>( + SK_ARRAY_COUNT(gTextVertexAttribs)); + } + fMaxVertices = kDefaultRequestedVerts; + // ignore return, no point in flushing again. + fDrawTarget->geometryHints(&fMaxVertices, NULL); + + int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads(); + if (fMaxVertices < kMinRequestedVerts) { + fMaxVertices = kDefaultRequestedVerts; + } else if (fMaxVertices > maxQuadVertices) { + // don't exceed the limit of the index buffer + fMaxVertices = maxQuadVertices; + } + bool success = fDrawTarget->reserveVertexAndIndexSpace(fMaxVertices, + 0, + GrTCast<void**>(&fVertices), + NULL); + GrAlwaysAssert(success); + SkASSERT(2*sizeof(GrPoint) == fDrawTarget->getDrawState().getVertexSize()); + } + + GrFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX); + GrFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY); + + fVertices[2*fCurrVertex].setRectFan(SkFixedToFloat(vx), + SkFixedToFloat(vy), + SkFixedToFloat(vx + width), + SkFixedToFloat(vy + height), + 2 * sizeof(SkPoint)); + fVertices[2*fCurrVertex+1].setRectFan(SkFixedToFloat(texture->normalizeFixedX(tx)), + SkFixedToFloat(texture->normalizeFixedY(ty)), + SkFixedToFloat(texture->normalizeFixedX(tx + width)), + SkFixedToFloat(texture->normalizeFixedY(ty + height)), + 2 * sizeof(SkPoint)); + fCurrVertex += 4; +} |