Index: src/gpu/GrAtlasTextContext.cpp |
diff --git a/src/gpu/GrAtlasTextContext.cpp b/src/gpu/GrAtlasTextContext.cpp |
index 09190c495b692527d10d5f927bac9699b44265e7..bb6a6ce90ef18cb7f4605f0f169d73f075ea93aa 100644 |
--- a/src/gpu/GrAtlasTextContext.cpp |
+++ b/src/gpu/GrAtlasTextContext.cpp |
@@ -6,15 +6,10 @@ |
*/ |
#include "GrAtlasTextContext.h" |
-#include "GrBatchFontCache.h" |
-#include "GrBatchFlushState.h" |
-#include "GrBatchTest.h" |
#include "GrBlurUtils.h" |
-#include "GrDefaultGeoProcFactory.h" |
#include "GrDrawContext.h" |
#include "GrDrawTarget.h" |
#include "GrFontScaler.h" |
-#include "GrResourceProvider.h" |
#include "GrStrokeInfo.h" |
#include "GrTextBlobCache.h" |
#include "GrTexturePriv.h" |
@@ -37,19 +32,9 @@ |
#include "SkTextBlob.h" |
#include "SkTextMapStateProc.h" |
-#include "batches/GrVertexBatch.h" |
- |
-#include "effects/GrBitmapTextGeoProc.h" |
-#include "effects/GrDistanceFieldGeoProc.h" |
+#include "batches/GrAtlasTextBatch.h" |
namespace { |
-static const size_t kLCDTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16); |
- |
-// position + local coord |
-static const size_t kColorTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16); |
- |
-static const size_t kGrayTextVASize = sizeof(SkPoint) + sizeof(GrColor) + sizeof(SkIPoint16); |
- |
static const int kMinDFFontSize = 18; |
static const int kSmallDFFontSize = 32; |
static const int kSmallDFFontLimit = 32; |
@@ -63,38 +48,6 @@ static const int kLargeDFFontLimit = 2 * kLargeDFFontSize; |
#endif |
SkDEBUGCODE(static const int kExpectedDistanceAdjustTableSize = 8;) |
-static const int kDistanceAdjustLumShift = 5; |
- |
-static const int kVerticesPerGlyph = 4; |
-static const int kIndicesPerGlyph = 6; |
- |
-static size_t get_vertex_stride(GrMaskFormat maskFormat) { |
- switch (maskFormat) { |
- case kA8_GrMaskFormat: |
- return kGrayTextVASize; |
- case kARGB_GrMaskFormat: |
- return kColorTextVASize; |
- default: |
- return kLCDTextVASize; |
- } |
-} |
- |
-static size_t get_vertex_stride_df(GrMaskFormat maskFormat, bool useLCDText) { |
- SkASSERT(maskFormat == kA8_GrMaskFormat); |
- if (useLCDText) { |
- return kLCDTextVASize; |
- } else { |
- return kGrayTextVASize; |
- } |
-} |
- |
-static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) { |
- unsigned r = SkColorGetR(c); |
- unsigned g = SkColorGetG(c); |
- unsigned b = SkColorGetB(c); |
- return GrColorPackRGBA(r, g, b, 0xff); |
-} |
- |
}; |
GrAtlasTextContext::GrAtlasTextContext(GrContext* context, const SkSurfaceProps& surfaceProps) |
@@ -102,7 +55,8 @@ GrAtlasTextContext::GrAtlasTextContext(GrContext* context, const SkSurfaceProps& |
, fDistanceAdjustTable(new DistanceAdjustTable) { |
// We overallocate vertices in our textblobs based on the assumption that A8 has the greatest |
// vertexStride |
- static_assert(kGrayTextVASize >= kColorTextVASize && kGrayTextVASize >= kLCDTextVASize, |
+ static_assert(GrAtlasTextBatch::kGrayTextVASize >= GrAtlasTextBatch::kColorTextVASize && |
+ GrAtlasTextBatch::kGrayTextVASize >= GrAtlasTextBatch::kLCDTextVASize, |
"vertex_attribute_changed"); |
fCurrStrike = nullptr; |
fCache = context->getTextBlobCache(); |
@@ -402,7 +356,7 @@ void GrAtlasTextContext::drawTextBlob(GrDrawContext* dc, GrRenderTarget* rt, |
// but we'd have to clear the subrun information |
fCache->remove(cacheBlob); |
cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, key, blurRec, skPaint, |
- kGrayTextVASize))); |
+ GrAtlasTextBatch::kGrayTextVASize))); |
this->regenerateTextBlob(cacheBlob, skPaint, grPaint.getColor(), viewMatrix, |
blob, x, y, drawFilter, clipRect, rt, clip); |
} else { |
@@ -430,9 +384,9 @@ void GrAtlasTextContext::drawTextBlob(GrDrawContext* dc, GrRenderTarget* rt, |
} else { |
if (canCache) { |
cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, key, blurRec, skPaint, |
- kGrayTextVASize))); |
+ GrAtlasTextBatch::kGrayTextVASize))); |
} else { |
- cacheBlob.reset(fCache->createBlob(blob, kGrayTextVASize)); |
+ cacheBlob.reset(fCache->createBlob(blob, GrAtlasTextBatch::kGrayTextVASize)); |
} |
this->regenerateTextBlob(cacheBlob, skPaint, grPaint.getColor(), viewMatrix, |
blob, x, y, drawFilter, clipRect, rt, clip); |
@@ -689,7 +643,7 @@ inline GrAtlasTextBlob* |
GrAtlasTextContext::setupDFBlob(int glyphCount, const SkPaint& origPaint, |
const SkMatrix& viewMatrix, SkPaint* dfPaint, |
SkScalar* textRatio) { |
- GrAtlasTextBlob* blob = fCache->createBlob(glyphCount, 1, kGrayTextVASize); |
+ GrAtlasTextBlob* blob = fCache->createBlob(glyphCount, 1, GrAtlasTextBatch::kGrayTextVASize); |
*dfPaint = origPaint; |
this->initDistanceFieldPaint(blob, dfPaint, textRatio, viewMatrix); |
@@ -729,7 +683,7 @@ GrAtlasTextContext::createDrawTextBlob(GrRenderTarget* rt, const GrClip& clip, |
fallbackTxt, fallbackPos, 2, offset, clipRect); |
} |
} else { |
- blob = fCache->createBlob(glyphCount, 1, kGrayTextVASize); |
+ blob = fCache->createBlob(glyphCount, 1, GrAtlasTextBatch::kGrayTextVASize); |
blob->fViewMatrix = viewMatrix; |
SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, &viewMatrix, false); |
@@ -769,7 +723,7 @@ GrAtlasTextContext::createDrawPosTextBlob(GrRenderTarget* rt, const GrClip& clip |
clipRect); |
} |
} else { |
- blob = fCache->createBlob(glyphCount, 1, kGrayTextVASize); |
+ blob = fCache->createBlob(glyphCount, 1, GrAtlasTextBatch::kGrayTextVASize); |
blob->fViewMatrix = viewMatrix; |
SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, &viewMatrix, false); |
this->internalDrawBMPPosText(blob, 0, cache, skPaint, paint.getColor(), viewMatrix, text, |
@@ -1090,7 +1044,7 @@ void GrAtlasTextContext::bmpAppendGlyph(GrAtlasTextBlob* blob, int runIndex, |
run.fInitialized = true; |
- size_t vertexStride = get_vertex_stride(format); |
+ size_t vertexStride = GrAtlasTextBatch::GetVertexStride(format); |
SkRect r; |
r.fLeft = SkIntToScalar(x); |
@@ -1168,7 +1122,8 @@ bool GrAtlasTextContext::dfAppendGlyph(GrAtlasTextBlob* blob, int runIndex, |
SkASSERT(glyph->fMaskFormat == kA8_GrMaskFormat); |
subRun->fMaskFormat = kA8_GrMaskFormat; |
- size_t vertexStride = get_vertex_stride_df(kA8_GrMaskFormat, subRun->fUseLCDText); |
+ size_t vertexStride = GrAtlasTextBatch::GetVertexStrideDf(kA8_GrMaskFormat, |
+ subRun->fUseLCDText); |
bool useColorVerts = !subRun->fUseLCDText; |
this->appendGlyphCommon(blob, &run, subRun, glyphRect, color, vertexStride, useColorVerts, |
@@ -1251,645 +1206,9 @@ inline void GrAtlasTextContext::appendGlyphCommon(GrAtlasTextBlob* blob, Run* ru |
} |
subRun->fGlyphEndIndex++; |
- subRun->fVertexEndIndex += vertexStride * kVerticesPerGlyph; |
+ subRun->fVertexEndIndex += vertexStride * GrAtlasTextBatch::kVerticesPerGlyph; |
} |
-class TextBatch : public GrVertexBatch { |
-public: |
- DEFINE_BATCH_CLASS_ID |
- |
- typedef GrAtlasTextContext::DistanceAdjustTable DistanceAdjustTable; |
- typedef GrAtlasTextBlob Blob; |
- typedef Blob::Run Run; |
- typedef Run::SubRunInfo TextInfo; |
- struct Geometry { |
- Blob* fBlob; |
- int fRun; |
- int fSubRun; |
- GrColor fColor; |
- SkScalar fTransX; |
- SkScalar fTransY; |
- }; |
- |
- static TextBatch* CreateBitmap(GrMaskFormat maskFormat, int glyphCount, |
- GrBatchFontCache* fontCache) { |
- TextBatch* batch = new TextBatch; |
- |
- batch->fFontCache = fontCache; |
- switch (maskFormat) { |
- case kA8_GrMaskFormat: |
- batch->fMaskType = kGrayscaleCoverageMask_MaskType; |
- break; |
- case kA565_GrMaskFormat: |
- batch->fMaskType = kLCDCoverageMask_MaskType; |
- break; |
- case kARGB_GrMaskFormat: |
- batch->fMaskType = kColorBitmapMask_MaskType; |
- break; |
- } |
- batch->fBatch.fNumGlyphs = glyphCount; |
- batch->fGeoCount = 1; |
- batch->fFilteredColor = 0; |
- batch->fFontCache = fontCache; |
- batch->fUseBGR = false; |
- return batch; |
- } |
- |
- static TextBatch* CreateDistanceField(int glyphCount, GrBatchFontCache* fontCache, |
- const DistanceAdjustTable* distanceAdjustTable, |
- SkColor filteredColor, bool isLCD, |
- bool useBGR) { |
- TextBatch* batch = new TextBatch; |
- |
- batch->fFontCache = fontCache; |
- batch->fMaskType = isLCD ? kLCDDistanceField_MaskType : kGrayscaleDistanceField_MaskType; |
- batch->fDistanceAdjustTable.reset(SkRef(distanceAdjustTable)); |
- batch->fFilteredColor = filteredColor; |
- batch->fUseBGR = useBGR; |
- batch->fBatch.fNumGlyphs = glyphCount; |
- batch->fGeoCount = 1; |
- return batch; |
- } |
- |
- // to avoid even the initial copy of the struct, we have a getter for the first item which |
- // is used to seed the batch with its initial geometry. After seeding, the client should call |
- // init() so the Batch can initialize itself |
- Geometry& geometry() { return fGeoData[0]; } |
- |
- void init() { |
- const Geometry& geo = fGeoData[0]; |
- fBatch.fColor = geo.fColor; |
- fBatch.fViewMatrix = geo.fBlob->fViewMatrix; |
- |
- // We don't yet position distance field text on the cpu, so we have to map the vertex bounds |
- // into device space |
- const Run& run = geo.fBlob->fRuns[geo.fRun]; |
- if (run.fSubRunInfo[geo.fSubRun].fDrawAsDistanceFields) { |
- SkRect bounds = run.fVertexBounds; |
- fBatch.fViewMatrix.mapRect(&bounds); |
- this->setBounds(bounds); |
- } else { |
- this->setBounds(run.fVertexBounds); |
- } |
- } |
- |
- const char* name() const override { return "TextBatch"; } |
- |
- SkString dumpInfo() const override { |
- SkString str; |
- |
- for (int i = 0; i < fGeoCount; ++i) { |
- str.appendf("%d: Color: 0x%08x Trans: %.2f,%.2f Runs: %d\n", |
- i, |
- fGeoData[i].fColor, |
- fGeoData[i].fTransX, |
- fGeoData[i].fTransY, |
- fGeoData[i].fBlob->fRunCount); |
- } |
- |
- str.append(INHERITED::dumpInfo()); |
- return str; |
- } |
- |
- void getInvariantOutputColor(GrInitInvariantOutput* out) const override { |
- if (kColorBitmapMask_MaskType == fMaskType) { |
- out->setUnknownFourComponents(); |
- } else { |
- out->setKnownFourComponents(fBatch.fColor); |
- } |
- } |
- |
- void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override { |
- switch (fMaskType) { |
- case kGrayscaleDistanceField_MaskType: |
- case kGrayscaleCoverageMask_MaskType: |
- out->setUnknownSingleComponent(); |
- break; |
- case kLCDCoverageMask_MaskType: |
- case kLCDDistanceField_MaskType: |
- out->setUnknownOpaqueFourComponents(); |
- out->setUsingLCDCoverage(); |
- break; |
- case kColorBitmapMask_MaskType: |
- out->setKnownSingleComponent(0xff); |
- } |
- } |
- |
-private: |
- void initBatchTracker(const GrPipelineOptimizations& opt) override { |
- // Handle any color overrides |
- if (!opt.readsColor()) { |
- fGeoData[0].fColor = GrColor_ILLEGAL; |
- } |
- opt.getOverrideColorIfSet(&fGeoData[0].fColor); |
- |
- // setup batch properties |
- fBatch.fColorIgnored = !opt.readsColor(); |
- fBatch.fColor = fGeoData[0].fColor; |
- fBatch.fUsesLocalCoords = opt.readsLocalCoords(); |
- fBatch.fCoverageIgnored = !opt.readsCoverage(); |
- } |
- |
- struct FlushInfo { |
- SkAutoTUnref<const GrVertexBuffer> fVertexBuffer; |
- SkAutoTUnref<const GrIndexBuffer> fIndexBuffer; |
- int fGlyphsToFlush; |
- int fVertexOffset; |
- }; |
- |
- void onPrepareDraws(Target* target) override { |
- // if we have RGB, then we won't have any SkShaders so no need to use a localmatrix. |
- // TODO actually only invert if we don't have RGBA |
- SkMatrix localMatrix; |
- if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix)) { |
- SkDebugf("Cannot invert viewmatrix\n"); |
- return; |
- } |
- |
- GrTexture* texture = fFontCache->getTexture(this->maskFormat()); |
- if (!texture) { |
- SkDebugf("Could not allocate backing texture for atlas\n"); |
- return; |
- } |
- |
- bool usesDistanceFields = this->usesDistanceFields(); |
- GrMaskFormat maskFormat = this->maskFormat(); |
- bool isLCD = this->isLCD(); |
- |
- SkAutoTUnref<const GrGeometryProcessor> gp; |
- if (usesDistanceFields) { |
- gp.reset(this->setupDfProcessor(this->viewMatrix(), fFilteredColor, this->color(), |
- texture)); |
- } else { |
- GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kNone_FilterMode); |
- gp.reset(GrBitmapTextGeoProc::Create(this->color(), |
- texture, |
- params, |
- maskFormat, |
- localMatrix, |
- this->usesLocalCoords())); |
- } |
- |
- FlushInfo flushInfo; |
- flushInfo.fGlyphsToFlush = 0; |
- size_t vertexStride = gp->getVertexStride(); |
- SkASSERT(vertexStride == (usesDistanceFields ? |
- get_vertex_stride_df(maskFormat, isLCD) : |
- get_vertex_stride(maskFormat))); |
- |
- target->initDraw(gp, this->pipeline()); |
- |
- int glyphCount = this->numGlyphs(); |
- const GrVertexBuffer* vertexBuffer; |
- |
- void* vertices = target->makeVertexSpace(vertexStride, |
- glyphCount * kVerticesPerGlyph, |
- &vertexBuffer, |
- &flushInfo.fVertexOffset); |
- flushInfo.fVertexBuffer.reset(SkRef(vertexBuffer)); |
- flushInfo.fIndexBuffer.reset(target->resourceProvider()->refQuadIndexBuffer()); |
- if (!vertices || !flushInfo.fVertexBuffer) { |
- SkDebugf("Could not allocate vertices\n"); |
- return; |
- } |
- |
- unsigned char* currVertex = reinterpret_cast<unsigned char*>(vertices); |
- |
- // We cache some values to avoid going to the glyphcache for the same fontScaler twice |
- // in a row |
- const SkDescriptor* desc = nullptr; |
- SkGlyphCache* cache = nullptr; |
- GrFontScaler* scaler = nullptr; |
- SkTypeface* typeface = nullptr; |
- |
- for (int i = 0; i < fGeoCount; i++) { |
- Geometry& args = fGeoData[i]; |
- Blob* blob = args.fBlob; |
- Run& run = blob->fRuns[args.fRun]; |
- TextInfo& info = run.fSubRunInfo[args.fSubRun]; |
- |
- uint64_t currentAtlasGen = fFontCache->atlasGeneration(maskFormat); |
- bool regenerateTextureCoords = info.fAtlasGeneration != currentAtlasGen || |
- info.fStrike->isAbandoned(); |
- bool regenerateColors; |
- if (usesDistanceFields) { |
- regenerateColors = !isLCD && run.fColor != args.fColor; |
- } else { |
- regenerateColors = kA8_GrMaskFormat == maskFormat && run.fColor != args.fColor; |
- } |
- bool regeneratePositions = args.fTransX != 0.f || args.fTransY != 0.f; |
- int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; |
- |
- // We regenerate both texture coords and colors in the blob itself, and update the |
- // atlas generation. If we don't end up purging any unused plots, we can avoid |
- // regenerating the coords. We could take a finer grained approach to updating texture |
- // coords but its not clear if the extra bookkeeping would offset any gains. |
- // To avoid looping over the glyphs twice, we do one loop and conditionally update color |
- // or coords as needed. One final note, if we have to break a run for an atlas eviction |
- // then we can't really trust the atlas has all of the correct data. Atlas evictions |
- // should be pretty rare, so we just always regenerate in those cases |
- if (regenerateTextureCoords || regenerateColors || regeneratePositions) { |
- // first regenerate texture coordinates / colors if need be |
- bool brokenRun = false; |
- |
- // Because the GrBatchFontCache may evict the strike a blob depends on using for |
- // generating its texture coords, we have to track whether or not the strike has |
- // been abandoned. If it hasn't been abandoned, then we can use the GrGlyph*s as is |
- // otherwise we have to get the new strike, and use that to get the correct glyphs. |
- // Because we do not have the packed ids, and thus can't look up our glyphs in the |
- // new strike, we instead keep our ref to the old strike and use the packed ids from |
- // it. These ids will still be valid as long as we hold the ref. When we are done |
- // updating our cache of the GrGlyph*s, we drop our ref on the old strike |
- bool regenerateGlyphs = false; |
- GrBatchTextStrike* strike = nullptr; |
- if (regenerateTextureCoords) { |
- info.fBulkUseToken.reset(); |
- |
- // We can reuse if we have a valid strike and our descriptors / typeface are the |
- // same. The override descriptor is only for the non distance field text within |
- // a run |
- const SkDescriptor* newDesc = (run.fOverrideDescriptor && !usesDistanceFields) ? |
- run.fOverrideDescriptor->getDesc() : |
- run.fDescriptor.getDesc(); |
- if (!cache || !SkTypeface::Equal(typeface, run.fTypeface) || |
- !(desc->equals(*newDesc))) { |
- if (cache) { |
- SkGlyphCache::AttachCache(cache); |
- } |
- desc = newDesc; |
- cache = SkGlyphCache::DetachCache(run.fTypeface, desc); |
- scaler = GrTextContext::GetGrFontScaler(cache); |
- strike = info.fStrike; |
- typeface = run.fTypeface; |
- } |
- |
- if (info.fStrike->isAbandoned()) { |
- regenerateGlyphs = true; |
- strike = fFontCache->getStrike(scaler); |
- } else { |
- strike = info.fStrike; |
- } |
- } |
- |
- for (int glyphIdx = 0; glyphIdx < glyphCount; glyphIdx++) { |
- if (regenerateTextureCoords) { |
- size_t glyphOffset = glyphIdx + info.fGlyphStartIndex; |
- |
- GrGlyph* glyph = blob->fGlyphs[glyphOffset]; |
- GrGlyph::PackedID id = glyph->fPackedID; |
- const SkGlyph& skGlyph = scaler->grToSkGlyph(id); |
- if (regenerateGlyphs) { |
- // Get the id from the old glyph, and use the new strike to lookup |
- // the glyph. |
- blob->fGlyphs[glyphOffset] = strike->getGlyph(skGlyph, id, maskFormat, |
- scaler); |
- } |
- glyph = blob->fGlyphs[glyphOffset]; |
- SkASSERT(glyph); |
- SkASSERT(id == glyph->fPackedID); |
- // We want to be able to assert this but cannot for testing purposes. |
- // once skbug:4143 has landed we can revist this assert |
- //SkASSERT(glyph->fMaskFormat == this->maskFormat()); |
- |
- if (!fFontCache->hasGlyph(glyph) && |
- !strike->addGlyphToAtlas(target, glyph, scaler, skGlyph, maskFormat)) { |
- this->flush(target, &flushInfo); |
- target->initDraw(gp, this->pipeline()); |
- brokenRun = glyphIdx > 0; |
- |
- SkDEBUGCODE(bool success =) strike->addGlyphToAtlas(target, |
- glyph, |
- scaler, |
- skGlyph, |
- maskFormat); |
- SkASSERT(success); |
- } |
- fFontCache->addGlyphToBulkAndSetUseToken(&info.fBulkUseToken, glyph, |
- target->currentToken()); |
- |
- // Texture coords are the last vertex attribute so we get a pointer to the |
- // first one and then map with stride in regenerateTextureCoords |
- intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices); |
- vertex += info.fVertexStartIndex; |
- vertex += vertexStride * glyphIdx * kVerticesPerGlyph; |
- vertex += vertexStride - sizeof(SkIPoint16); |
- |
- this->regenerateTextureCoords(glyph, vertex, vertexStride); |
- } |
- |
- if (regenerateColors) { |
- intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices); |
- vertex += info.fVertexStartIndex; |
- vertex += vertexStride * glyphIdx * kVerticesPerGlyph + sizeof(SkPoint); |
- this->regenerateColors(vertex, vertexStride, args.fColor); |
- } |
- |
- if (regeneratePositions) { |
- intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices); |
- vertex += info.fVertexStartIndex; |
- vertex += vertexStride * glyphIdx * kVerticesPerGlyph; |
- SkScalar transX = args.fTransX; |
- SkScalar transY = args.fTransY; |
- this->regeneratePositions(vertex, vertexStride, transX, transY); |
- } |
- flushInfo.fGlyphsToFlush++; |
- } |
- |
- // We my have changed the color so update it here |
- run.fColor = args.fColor; |
- if (regenerateTextureCoords) { |
- if (regenerateGlyphs) { |
- info.fStrike.reset(SkRef(strike)); |
- } |
- info.fAtlasGeneration = brokenRun ? GrBatchAtlas::kInvalidAtlasGeneration : |
- fFontCache->atlasGeneration(maskFormat); |
- } |
- } else { |
- flushInfo.fGlyphsToFlush += glyphCount; |
- |
- // set use tokens for all of the glyphs in our subrun. This is only valid if we |
- // have a valid atlas generation |
- fFontCache->setUseTokenBulk(info.fBulkUseToken, target->currentToken(), maskFormat); |
- } |
- |
- // now copy all vertices |
- size_t byteCount = info.fVertexEndIndex - info.fVertexStartIndex; |
- memcpy(currVertex, blob->fVertices + info.fVertexStartIndex, byteCount); |
- |
- currVertex += byteCount; |
- } |
- // Make sure to attach the last cache if applicable |
- if (cache) { |
- SkGlyphCache::AttachCache(cache); |
- } |
- this->flush(target, &flushInfo); |
- } |
- |
- TextBatch() : INHERITED(ClassID()) {} // initialized in factory functions. |
- |
- ~TextBatch() { |
- for (int i = 0; i < fGeoCount; i++) { |
- fGeoData[i].fBlob->unref(); |
- } |
- } |
- |
- GrMaskFormat maskFormat() const { |
- switch (fMaskType) { |
- case kLCDCoverageMask_MaskType: |
- return kA565_GrMaskFormat; |
- case kColorBitmapMask_MaskType: |
- return kARGB_GrMaskFormat; |
- case kGrayscaleCoverageMask_MaskType: |
- case kGrayscaleDistanceField_MaskType: |
- case kLCDDistanceField_MaskType: |
- return kA8_GrMaskFormat; |
- } |
- return kA8_GrMaskFormat; // suppress warning |
- } |
- |
- bool usesDistanceFields() const { |
- return kGrayscaleDistanceField_MaskType == fMaskType || |
- kLCDDistanceField_MaskType == fMaskType; |
- } |
- |
- bool isLCD() const { |
- return kLCDCoverageMask_MaskType == fMaskType || |
- kLCDDistanceField_MaskType == fMaskType; |
- } |
- |
- void regenerateTextureCoords(GrGlyph* glyph, intptr_t vertex, size_t vertexStride) { |
- int width = glyph->fBounds.width(); |
- int height = glyph->fBounds.height(); |
- |
- int u0, v0, u1, v1; |
- if (this->usesDistanceFields()) { |
- u0 = glyph->fAtlasLocation.fX + SK_DistanceFieldInset; |
- v0 = glyph->fAtlasLocation.fY + SK_DistanceFieldInset; |
- u1 = u0 + width - 2 * SK_DistanceFieldInset; |
- v1 = v0 + height - 2 * SK_DistanceFieldInset; |
- } else { |
- u0 = glyph->fAtlasLocation.fX; |
- v0 = glyph->fAtlasLocation.fY; |
- u1 = u0 + width; |
- v1 = v0 + height; |
- } |
- |
- SkIPoint16* textureCoords; |
- // V0 |
- textureCoords = reinterpret_cast<SkIPoint16*>(vertex); |
- textureCoords->set(u0, v0); |
- vertex += vertexStride; |
- |
- // V1 |
- textureCoords = reinterpret_cast<SkIPoint16*>(vertex); |
- textureCoords->set(u0, v1); |
- vertex += vertexStride; |
- |
- // V2 |
- textureCoords = reinterpret_cast<SkIPoint16*>(vertex); |
- textureCoords->set(u1, v1); |
- vertex += vertexStride; |
- |
- // V3 |
- textureCoords = reinterpret_cast<SkIPoint16*>(vertex); |
- textureCoords->set(u1, v0); |
- } |
- |
- void regenerateColors(intptr_t vertex, size_t vertexStride, GrColor color) { |
- for (int i = 0; i < kVerticesPerGlyph; i++) { |
- SkColor* vcolor = reinterpret_cast<SkColor*>(vertex); |
- *vcolor = color; |
- vertex += vertexStride; |
- } |
- } |
- |
- void regeneratePositions(intptr_t vertex, size_t vertexStride, SkScalar transX, |
- SkScalar transY) { |
- for (int i = 0; i < kVerticesPerGlyph; i++) { |
- SkPoint* point = reinterpret_cast<SkPoint*>(vertex); |
- point->fX += transX; |
- point->fY += transY; |
- vertex += vertexStride; |
- } |
- } |
- |
- void flush(GrVertexBatch::Target* target, FlushInfo* flushInfo) { |
- GrVertices vertices; |
- int maxGlyphsPerDraw = flushInfo->fIndexBuffer->maxQuads(); |
- vertices.initInstanced(kTriangles_GrPrimitiveType, flushInfo->fVertexBuffer, |
- flushInfo->fIndexBuffer, flushInfo->fVertexOffset, |
- kVerticesPerGlyph, kIndicesPerGlyph, flushInfo->fGlyphsToFlush, |
- maxGlyphsPerDraw); |
- target->draw(vertices); |
- flushInfo->fVertexOffset += kVerticesPerGlyph * flushInfo->fGlyphsToFlush; |
- flushInfo->fGlyphsToFlush = 0; |
- } |
- |
- GrColor color() const { return fBatch.fColor; } |
- const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; } |
- bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } |
- int numGlyphs() const { return fBatch.fNumGlyphs; } |
- |
- bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { |
- TextBatch* that = t->cast<TextBatch>(); |
- if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), |
- that->bounds(), caps)) { |
- return false; |
- } |
- |
- if (fMaskType != that->fMaskType) { |
- return false; |
- } |
- |
- if (!this->usesDistanceFields()) { |
- // TODO we can often batch across LCD text if we have dual source blending and don't |
- // have to use the blend constant |
- if (kGrayscaleCoverageMask_MaskType != fMaskType && this->color() != that->color()) { |
- return false; |
- } |
- if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) { |
- return false; |
- } |
- } else { |
- if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) { |
- return false; |
- } |
- |
- if (fFilteredColor != that->fFilteredColor) { |
- return false; |
- } |
- |
- if (fUseBGR != that->fUseBGR) { |
- return false; |
- } |
- |
- // TODO see note above |
- if (kLCDDistanceField_MaskType == fMaskType && this->color() != that->color()) { |
- return false; |
- } |
- } |
- |
- fBatch.fNumGlyphs += that->numGlyphs(); |
- |
- // Reallocate space for geo data if necessary and then import that's geo data. |
- int newGeoCount = that->fGeoCount + fGeoCount; |
- // We assume (and here enforce) that the allocation size is the smallest power of two that |
- // is greater than or equal to the number of geometries (and at least |
- // kMinGeometryAllocated). |
- int newAllocSize = GrNextPow2(newGeoCount); |
- int currAllocSize = SkTMax<int>(kMinGeometryAllocated, GrNextPow2(fGeoCount)); |
- |
- if (newGeoCount > currAllocSize) { |
- fGeoData.realloc(newAllocSize); |
- } |
- |
- memcpy(&fGeoData[fGeoCount], that->fGeoData.get(), that->fGeoCount * sizeof(Geometry)); |
- // We steal the ref on the blobs from the other TextBatch and set its count to 0 so that |
- // it doesn't try to unref them. |
-#ifdef SK_DEBUG |
- for (int i = 0; i < that->fGeoCount; ++i) { |
- that->fGeoData.get()[i].fBlob = (Blob*)0x1; |
- } |
-#endif |
- that->fGeoCount = 0; |
- fGeoCount = newGeoCount; |
- |
- this->joinBounds(that->bounds()); |
- return true; |
- } |
- |
- // TODO just use class params |
- // TODO trying to figure out why lcd is so whack |
- GrGeometryProcessor* setupDfProcessor(const SkMatrix& viewMatrix, SkColor filteredColor, |
- GrColor color, GrTexture* texture) { |
- GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBilerp_FilterMode); |
- bool isLCD = this->isLCD(); |
- // set up any flags |
- uint32_t flags = viewMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0; |
- |
- // see if we need to create a new effect |
- if (isLCD) { |
- flags |= kUseLCD_DistanceFieldEffectFlag; |
- flags |= viewMatrix.rectStaysRect() ? kRectToRect_DistanceFieldEffectFlag : 0; |
- flags |= fUseBGR ? kBGR_DistanceFieldEffectFlag : 0; |
- |
- 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]; |
- GrDistanceFieldLCDTextGeoProc::DistanceAdjust widthAdjust = |
- GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(redCorrection, |
- greenCorrection, |
- blueCorrection); |
- |
- return GrDistanceFieldLCDTextGeoProc::Create(color, |
- viewMatrix, |
- texture, |
- params, |
- widthAdjust, |
- flags, |
- this->usesLocalCoords()); |
- } else { |
- flags |= kColorAttr_DistanceFieldEffectFlag; |
-#ifdef SK_GAMMA_APPLY_TO_A8 |
- U8CPU lum = SkColorSpaceLuminance::computeLuminance(SK_GAMMA_EXPONENT, filteredColor); |
- float correction = (*fDistanceAdjustTable)[lum >> kDistanceAdjustLumShift]; |
- return GrDistanceFieldA8TextGeoProc::Create(color, |
- viewMatrix, |
- texture, |
- params, |
- correction, |
- flags, |
- this->usesLocalCoords()); |
-#else |
- return GrDistanceFieldA8TextGeoProc::Create(color, |
- viewMatrix, |
- texture, |
- params, |
- flags, |
- this->usesLocalCoords()); |
-#endif |
- } |
- |
- } |
- |
- struct BatchTracker { |
- GrColor fColor; |
- SkMatrix fViewMatrix; |
- bool fUsesLocalCoords; |
- bool fColorIgnored; |
- bool fCoverageIgnored; |
- int fNumGlyphs; |
- }; |
- |
- BatchTracker fBatch; |
- // The minimum number of Geometry we will try to allocate. |
- enum { kMinGeometryAllocated = 4 }; |
- SkAutoSTMalloc<kMinGeometryAllocated, Geometry> fGeoData; |
- int fGeoCount; |
- |
- enum MaskType { |
- kGrayscaleCoverageMask_MaskType, |
- kLCDCoverageMask_MaskType, |
- kColorBitmapMask_MaskType, |
- kGrayscaleDistanceField_MaskType, |
- kLCDDistanceField_MaskType, |
- } fMaskType; |
- bool fUseBGR; // fold this into the enum? |
- |
- GrBatchFontCache* fFontCache; |
- |
- // Distance field properties |
- SkAutoTUnref<const DistanceAdjustTable> fDistanceAdjustTable; |
- SkColor fFilteredColor; |
- |
- typedef GrVertexBatch INHERITED; |
-}; |
- |
void GrAtlasTextContext::flushRunAsPaths(GrDrawContext* dc, GrRenderTarget* rt, |
const SkTextBlobRunIterator& it, |
const GrClip& clip, const SkPaint& skPaint, |
@@ -1942,7 +1261,7 @@ GrAtlasTextContext::createBatch(GrAtlasTextBlob* cacheBlob, const PerSubRunInfo& |
subRunColor = color; |
} |
- TextBatch* batch; |
+ GrAtlasTextBatch* batch; |
if (info.fDrawAsDistanceFields) { |
SkColor filteredColor; |
SkColorFilter* colorFilter = skPaint.getColorFilter(); |
@@ -1952,13 +1271,13 @@ GrAtlasTextContext::createBatch(GrAtlasTextBlob* cacheBlob, const PerSubRunInfo& |
filteredColor = skPaint.getColor(); |
} |
bool useBGR = SkPixelGeometryIsBGR(fSurfaceProps.pixelGeometry()); |
- batch = TextBatch::CreateDistanceField(glyphCount, fContext->getBatchFontCache(), |
- fDistanceAdjustTable, filteredColor, |
- info.fUseLCDText, useBGR); |
+ batch = GrAtlasTextBatch::CreateDistanceField(glyphCount, fContext->getBatchFontCache(), |
+ fDistanceAdjustTable, filteredColor, |
+ info.fUseLCDText, useBGR); |
} else { |
- batch = TextBatch::CreateBitmap(format, glyphCount, fContext->getBatchFontCache()); |
+ batch = GrAtlasTextBatch::CreateBitmap(format, glyphCount, fContext->getBatchFontCache()); |
} |
- TextBatch::Geometry& geometry = batch->geometry(); |
+ GrAtlasTextBatch::Geometry& geometry = batch->geometry(); |
geometry.fBlob = SkRef(cacheBlob); |
geometry.fRun = run; |
geometry.fSubRun = subRun; |