diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core/SkDescriptor.h | 14 | ||||
-rw-r--r-- | src/core/SkPaint.cpp | 13 | ||||
-rwxr-xr-x | src/gpu/GrBitmapTextContext.cpp | 244 | ||||
-rw-r--r-- | src/gpu/GrBitmapTextContext.h | 77 |
4 files changed, 238 insertions, 110 deletions
diff --git a/src/core/SkDescriptor.h b/src/core/SkDescriptor.h index 22ec29316f..0693ccfe60 100644 --- a/src/core/SkDescriptor.h +++ b/src/core/SkDescriptor.h @@ -134,7 +134,13 @@ private: class SkAutoDescriptor : SkNoncopyable { public: - SkAutoDescriptor(size_t size) { + SkAutoDescriptor() : fDesc(NULL) {} + SkAutoDescriptor(size_t size) : fDesc(NULL) { this->reset(size); } + + ~SkAutoDescriptor() { this->free(); } + + void reset(size_t size) { + this->free(); if (size <= sizeof(fStorage)) { fDesc = (SkDescriptor*)(void*)fStorage; } else { @@ -142,14 +148,14 @@ public: } } - ~SkAutoDescriptor() { + SkDescriptor* getDesc() const { SkASSERT(fDesc); return fDesc; } +private: + void free() { if (fDesc != (SkDescriptor*)(void*)fStorage) { SkDescriptor::Free(fDesc); } } - SkDescriptor* getDesc() const { return fDesc; } -private: enum { kStorageSize = sizeof(SkDescriptor) + sizeof(SkDescriptor::Entry) + sizeof(SkScalerContext::Rec) // for rec diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp index 24281d7cff..2c1745d00b 100644 --- a/src/core/SkPaint.cpp +++ b/src/core/SkPaint.cpp @@ -1705,9 +1705,9 @@ static void test_desc(const SkScalerContext::Rec& rec, #endif /* see the note on ignoreGamma on descriptorProc */ -const SkData* SkPaint::getScalerContextDescriptor(const SkDeviceProperties* deviceProperties, - const SkMatrix* deviceMatrix, - bool ignoreGamma) const { +void SkPaint::getScalerContextDescriptor(SkAutoDescriptor* ad, + const SkDeviceProperties* deviceProperties, + const SkMatrix* deviceMatrix, bool ignoreGamma) const { SkScalerContext::Rec rec; SkPathEffect* pe = this->getPathEffect(); @@ -1718,9 +1718,8 @@ const SkData* SkPaint::getScalerContextDescriptor(const SkDeviceProperties* devi size_t descSize = fill_out_rec(*this, &rec, deviceProperties, deviceMatrix, ignoreGamma, pe, &peBuffer, mf, &mfBuffer, ra, &raBuffer); - SkASSERT(SkAlign4(descSize) == descSize); - SkData* data = SkData::NewUninitialized(descSize); - SkDescriptor* desc = reinterpret_cast<SkDescriptor*>(data->writable_data()); + ad->reset(descSize); + SkDescriptor* desc = ad->getDesc(); write_out_descriptor(desc, rec, pe, &peBuffer, mf, &mfBuffer, ra, &raBuffer, descSize); @@ -1729,8 +1728,6 @@ const SkData* SkPaint::getScalerContextDescriptor(const SkDeviceProperties* devi #ifdef TEST_DESC test_desc(rec, pe, &peBuffer, mf, &mfBuffer, ra, &raBuffer, desc, descSize); #endif - - return data; } /* diff --git a/src/gpu/GrBitmapTextContext.cpp b/src/gpu/GrBitmapTextContext.cpp index 45926673ef..605703d1c6 100755 --- a/src/gpu/GrBitmapTextContext.cpp +++ b/src/gpu/GrBitmapTextContext.cpp @@ -101,31 +101,80 @@ bool GrBitmapTextContextB::MustRegenerateBlob(const BitmapTextBlob& blob, const paint.getMaskFilter() || paint.getPathEffect() || paint.getStyle() != blob.fStyle; } + +inline SkGlyphCache* GrBitmapTextContextB::setupCache(BitmapTextBlob::Run* run, + const SkPaint& skPaint, + const SkMatrix& viewMatrix) { + skPaint.getScalerContextDescriptor(&run->fDescriptor, &fDeviceProperties, &viewMatrix, false); + run->fTypeface.reset(SkSafeRef(skPaint.getTypeface())); + return SkGlyphCache::DetachCache(run->fTypeface, run->fDescriptor.getDesc()); +} + +inline void GrBitmapTextContextB::BlobGlyphCount(int* glyphCount, int* runCount, + const SkTextBlob* blob) { + SkTextBlob::RunIterator itCounter(blob); + for (; !itCounter.done(); itCounter.next(), (*runCount)++) { + *glyphCount += itCounter.glyphCount(); + } +} + +GrBitmapTextContextB::BitmapTextBlob* GrBitmapTextContextB::CreateBlob(int glyphCount, + int runCount) { + // We allocate size for the BitmapTextBlob itself, plus size for the vertices array, + // and size for the glyphIds array. + SK_COMPILE_ASSERT(kGrayTextVASize >= kColorTextVASize && kGrayTextVASize >= kLCDTextVASize, + vertex_attribute_changed); + size_t verticesCount = glyphCount * kVerticesPerGlyph * kGrayTextVASize; + size_t length = sizeof(BitmapTextBlob) + + verticesCount + + glyphCount * sizeof(GrGlyph::PackedID) + + sizeof(BitmapTextBlob::Run) * runCount; + + BitmapTextBlob* cacheBlob = SkNEW_PLACEMENT(sk_malloc_throw(length), BitmapTextBlob); + + // setup offsets for vertices / glyphs + cacheBlob->fVertices = sizeof(BitmapTextBlob) + reinterpret_cast<unsigned char*>(cacheBlob); + cacheBlob->fGlyphIDs = + reinterpret_cast<GrGlyph::PackedID*>(cacheBlob->fVertices + verticesCount); + cacheBlob->fRuns = reinterpret_cast<BitmapTextBlob::Run*>(cacheBlob->fGlyphIDs + glyphCount); + + // Initialize runs + for (int i = 0; i < runCount; i++) { + SkNEW_PLACEMENT(&cacheBlob->fRuns[i], BitmapTextBlob::Run); + } + cacheBlob->fRunCount = runCount; + return cacheBlob; +} + void GrBitmapTextContextB::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, const SkPaint& skPaint, const SkMatrix& viewMatrix, const SkTextBlob* blob, SkScalar x, SkScalar y, SkDrawFilter* drawFilter, const SkIRect& clipBounds) { BitmapTextBlob* cacheBlob; BitmapTextBlob** foundBlob = fCache.find(blob->uniqueID()); - SkIRect clipRect; clip.getConservativeBounds(rt->width(), rt->height(), &clipRect); if (foundBlob) { cacheBlob = *foundBlob; if (MustRegenerateBlob(*cacheBlob, skPaint, viewMatrix, x, y)) { - // We can get away with reusing the blob if there are no outstanding refs on it. - // However, we still have to reset all of the runs. - if (!cacheBlob->unique()) { - cacheBlob->unref(); - cacheBlob = SkNEW(BitmapTextBlob); - fCache.set(blob->uniqueID(), cacheBlob); - } + // We have to remake the blob because changes may invalidate our masks. + // TODO we could probably get away reuse most of the time if the pointer is unique, + // but we'd have to clear the subrun information + cacheBlob->unref(); + int glyphCount = 0; + int runCount = 0; + BlobGlyphCount(&glyphCount, &runCount, blob); + cacheBlob = CreateBlob(glyphCount, runCount); + fCache.set(blob->uniqueID(), cacheBlob); this->regenerateTextBlob(cacheBlob, skPaint, viewMatrix, blob, x, y, drawFilter, clipRect); } } else { - cacheBlob = SkNEW(BitmapTextBlob); + int glyphCount = 0; + int runCount = 0; + BlobGlyphCount(&glyphCount, &runCount, blob); + cacheBlob = CreateBlob(glyphCount, runCount); fCache.set(blob->uniqueID(), cacheBlob); this->regenerateTextBlob(cacheBlob, skPaint, viewMatrix, blob, x, y, drawFilter, clipRect); } @@ -147,13 +196,13 @@ void GrBitmapTextContextB::regenerateTextBlob(BitmapTextBlob* cacheBlob, cacheBlob->fX = x; cacheBlob->fY = y; cacheBlob->fStyle = skPaint.getStyle(); - cacheBlob->fRuns.reset(blob->fRunCount); // Regenerate textblob SkPaint runPaint = skPaint; SkTextBlob::RunIterator it(blob); for (int run = 0; !it.done(); it.next(), run++) { - size_t textLen = it.glyphCount() * sizeof(uint16_t); + int glyphCount = it.glyphCount(); + size_t textLen = glyphCount * sizeof(uint16_t); const SkPoint& offset = it.offset(); // applyFontToPaint() always overwrites the exact same attributes, // so it is safe to not re-seed the paint for this reason. @@ -167,19 +216,33 @@ void GrBitmapTextContextB::regenerateTextBlob(BitmapTextBlob* cacheBlob, runPaint.setFlags(fGpuDevice->filterTextFlags(runPaint)); + SkGlyphCache* cache = this->setupCache(&cacheBlob->fRuns[run], runPaint, viewMatrix); + + // setup vertex / glyphIndex for the new run + if (run > 0) { + PerSubRunInfo& newRun = cacheBlob->fRuns[run].fSubRunInfo.back(); + PerSubRunInfo& lastRun = cacheBlob->fRuns[run - 1].fSubRunInfo.back(); + + newRun.fVertexStartIndex = lastRun.fVertexEndIndex; + newRun.fVertexEndIndex = lastRun.fVertexEndIndex; + + newRun.fGlyphStartIndex = lastRun.fGlyphEndIndex; + newRun.fGlyphEndIndex = lastRun.fGlyphEndIndex; + } + switch (it.positioning()) { case SkTextBlob::kDefault_Positioning: - this->internalDrawText(cacheBlob, run, runPaint, viewMatrix, + this->internalDrawText(cacheBlob, run, cache, runPaint, viewMatrix, (const char *)it.glyphs(), textLen, x + offset.x(), y + offset.y(), clipRect); break; case SkTextBlob::kHorizontal_Positioning: - this->internalDrawPosText(cacheBlob, run, runPaint, viewMatrix, + this->internalDrawPosText(cacheBlob, run, cache, runPaint, viewMatrix, (const char*)it.glyphs(), textLen, it.pos(), 1, SkPoint::Make(x, y + offset.y()), clipRect); break; case SkTextBlob::kFull_Positioning: - this->internalDrawPosText(cacheBlob, run, runPaint, viewMatrix, + this->internalDrawPosText(cacheBlob, run, cache, runPaint, viewMatrix, (const char*)it.glyphs(), textLen, it.pos(), 2, SkPoint::Make(x, y), clipRect); break; @@ -189,6 +252,8 @@ void GrBitmapTextContextB::regenerateTextBlob(BitmapTextBlob* cacheBlob, // A draw filter may change the paint arbitrarily, so we must re-seed in this case. runPaint = skPaint; } + + SkGlyphCache::AttachCache(cache); } } @@ -197,21 +262,26 @@ void GrBitmapTextContextB::onDrawText(GrRenderTarget* rt, const GrClip& clip, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkIRect& regionClipBounds) { - SkAutoTUnref<BitmapTextBlob> blob(SkNEW(BitmapTextBlob)); + int glyphCount = skPaint.countText(text, byteLength); + SkAutoTUnref<BitmapTextBlob> blob(CreateBlob(glyphCount, 1)); blob->fViewMatrix = viewMatrix; blob->fX = x; blob->fY = y; blob->fStyle = skPaint.getStyle(); - blob->fRuns.push_back(); SkIRect clipRect; clip.getConservativeBounds(rt->width(), rt->height(), &clipRect); - this->internalDrawText(blob, 0, skPaint, viewMatrix, text, byteLength, x, y, clipRect); + + // setup cache + SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, viewMatrix); + this->internalDrawText(blob, 0, cache, skPaint, viewMatrix, text, byteLength, x, y, clipRect); + SkGlyphCache::AttachCache(cache); + this->flush(fContext->getTextTarget(), blob, rt, paint, clip, viewMatrix, skPaint.getAlpha()); } void GrBitmapTextContextB::internalDrawText(BitmapTextBlob* blob, int runIndex, - const SkPaint& skPaint, + SkGlyphCache* cache, const SkPaint& skPaint, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkIRect& clipRect) { @@ -226,12 +296,6 @@ void GrBitmapTextContextB::internalDrawText(BitmapTextBlob* blob, int runIndex, SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc(); // Get GrFontScaler from cache - BitmapTextBlob::Run& run = blob->fRuns[runIndex]; - run.fDescriptor.reset(skPaint.getScalerContextDescriptor(&fDeviceProperties, &viewMatrix, - false)); - run.fTypeface.reset(SkSafeRef(skPaint.getTypeface())); - const SkDescriptor* desc = reinterpret_cast<const SkDescriptor*>(run.fDescriptor->data()); - SkGlyphCache* cache = SkGlyphCache::DetachCache(run.fTypeface, desc); GrFontScaler* fontScaler = GetGrFontScaler(cache); // transform our starting point @@ -303,8 +367,6 @@ void GrBitmapTextContextB::internalDrawText(BitmapTextBlob* blob, int runIndex, fx += glyph.fAdvanceX; fy += glyph.fAdvanceY; } - - SkGlyphCache::AttachCache(cache); } void GrBitmapTextContextB::onDrawPosText(GrRenderTarget* rt, const GrClip& clip, @@ -313,20 +375,25 @@ void GrBitmapTextContextB::onDrawPosText(GrRenderTarget* rt, const GrClip& clip, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset, const SkIRect& regionClipBounds) { - SkAutoTUnref<BitmapTextBlob> blob(SkNEW(BitmapTextBlob)); + int glyphCount = skPaint.countText(text, byteLength); + SkAutoTUnref<BitmapTextBlob> blob(CreateBlob(glyphCount, 1)); blob->fStyle = skPaint.getStyle(); - blob->fRuns.push_back(); blob->fViewMatrix = viewMatrix; SkIRect clipRect; clip.getConservativeBounds(rt->width(), rt->height(), &clipRect); - this->internalDrawPosText(blob, 0, skPaint, viewMatrix, text, byteLength, pos, + + // setup cache + SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, viewMatrix); + this->internalDrawPosText(blob, 0, cache, skPaint, viewMatrix, text, byteLength, pos, scalarsPerPosition, offset, clipRect); + SkGlyphCache::AttachCache(cache); + this->flush(fContext->getTextTarget(), blob, rt, paint, clip, viewMatrix, fSkPaint.getAlpha()); } void GrBitmapTextContextB::internalDrawPosText(BitmapTextBlob* blob, int runIndex, - const SkPaint& skPaint, + SkGlyphCache* cache, const SkPaint& skPaint, const SkMatrix& viewMatrix, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, @@ -343,12 +410,6 @@ void GrBitmapTextContextB::internalDrawPosText(BitmapTextBlob* blob, int runInde SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc(); // Get GrFontScaler from cache - BitmapTextBlob::Run& run = blob->fRuns[runIndex]; - run.fDescriptor.reset(skPaint.getScalerContextDescriptor(&fDeviceProperties, &viewMatrix, - false)); - run.fTypeface.reset(SkSafeRef(skPaint.getTypeface())); - const SkDescriptor* desc = reinterpret_cast<const SkDescriptor*>(run.fDescriptor->data()); - SkGlyphCache* cache = SkGlyphCache::DetachCache(run.fTypeface, desc); GrFontScaler* fontScaler = GetGrFontScaler(cache); const char* stop = text + byteLength; @@ -487,7 +548,6 @@ void GrBitmapTextContextB::internalDrawPosText(BitmapTextBlob* blob, int runInde } } } - SkGlyphCache::AttachCache(cache); } static size_t get_vertex_stride(GrMaskFormat maskFormat) { @@ -540,13 +600,28 @@ void GrBitmapTextContextB::appendGlyph(BitmapTextBlob* blob, int runIndex, GrGly blob->fBigGlyphs.push_back(BitmapTextBlob::BigGlyph(*glyph->fPath, vx, vy)); return; } + + Run& run = blob->fRuns[runIndex]; + GrMaskFormat format = glyph->fMaskFormat; - size_t vertexStride = get_vertex_stride(format); - BitmapTextBlob::Run& run = blob->fRuns[runIndex]; - int glyphIdx = run.fInfos[format].fGlyphIDs.count(); - *run.fInfos[format].fGlyphIDs.append() = packed; - run.fInfos[format].fVertices.append(static_cast<int>(vertexStride * kVerticesPerGlyph)); + PerSubRunInfo* subRun = &run.fSubRunInfo.back(); + if (run.fInitialized && subRun->fMaskFormat != format) { + PerSubRunInfo* newSubRun = &run.fSubRunInfo.push_back(); + newSubRun->fGlyphStartIndex = subRun->fGlyphEndIndex; + newSubRun->fGlyphEndIndex = subRun->fGlyphEndIndex; + + newSubRun->fVertexStartIndex = subRun->fVertexEndIndex; + newSubRun->fVertexEndIndex = subRun->fVertexEndIndex; + + subRun = newSubRun; + } + + run.fInitialized = true; + subRun->fMaskFormat = format; + blob->fGlyphIDs[subRun->fGlyphEndIndex] = packed; + + size_t vertexStride = get_vertex_stride(format); SkRect r; r.fLeft = SkIntToScalar(x); @@ -558,8 +633,7 @@ void GrBitmapTextContextB::appendGlyph(BitmapTextBlob* blob, int runIndex, GrGly GrColor color = fPaint.getColor(); run.fColor = color; - intptr_t vertex = reinterpret_cast<intptr_t>(run.fInfos[format].fVertices.begin()); - vertex += vertexStride * glyphIdx * kVerticesPerGlyph; + intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices + subRun->fVertexEndIndex); // V0 SkPoint* position = reinterpret_cast<SkPoint*>(vertex); @@ -595,27 +669,32 @@ void GrBitmapTextContextB::appendGlyph(BitmapTextBlob* blob, int runIndex, GrGly SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)); *colorPtr = color; } + + subRun->fGlyphEndIndex++; + subRun->fVertexEndIndex += vertexStride * kVerticesPerGlyph; } class BitmapTextBatch : public GrBatch { public: typedef GrBitmapTextContextB::BitmapTextBlob Blob; typedef Blob::Run Run; - typedef Run::PerFormatInfo TextInfo; + typedef Run::SubRunInfo TextInfo; struct Geometry { Geometry() {} Geometry(const Geometry& geometry) : fBlob(SkRef(geometry.fBlob.get())) , fRun(geometry.fRun) + , fSubRun(geometry.fSubRun) , fColor(geometry.fColor) {} SkAutoTUnref<Blob> fBlob; int fRun; + int fSubRun; GrColor fColor; }; static GrBatch* Create(const Geometry& geometry, GrColor color, GrMaskFormat maskFormat, - GrBatchFontCache* fontCache) { - return SkNEW_ARGS(BitmapTextBatch, (geometry, color, maskFormat, fontCache)); + int glyphCount, GrBatchFontCache* fontCache) { + return SkNEW_ARGS(BitmapTextBatch, (geometry, color, maskFormat, glyphCount, fontCache)); } const char* name() const override { return "BitmapTextBatch"; } @@ -718,12 +797,12 @@ public: Geometry& args = fGeoData[i]; Blob* blob = args.fBlob; Run& run = blob->fRuns[args.fRun]; - TextInfo& info = run.fInfos[fMaskFormat]; + TextInfo& info = run.fSubRunInfo[args.fSubRun]; uint64_t currentAtlasGen = fFontCache->atlasGeneration(fMaskFormat); bool regenerateTextureCoords = info.fAtlasGeneration != currentAtlasGen; bool regenerateColors = kA8_GrMaskFormat == fMaskFormat && run.fColor != args.fColor; - int glyphCount = info.fGlyphIDs.count(); + 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 @@ -741,13 +820,13 @@ public: GrBatchTextStrike* strike = NULL; bool brokenRun = false; if (regenerateTextureCoords) { - desc = reinterpret_cast<const SkDescriptor*>(run.fDescriptor->data()); + desc = run.fDescriptor.getDesc(); cache = SkGlyphCache::DetachCache(run.fTypeface, desc); scaler = GrTextContext::GetGrFontScaler(cache); strike = fFontCache->getStrike(scaler); } for (int glyphIdx = 0; glyphIdx < glyphCount; glyphIdx++) { - GrGlyph::PackedID glyphID = info.fGlyphIDs[glyphIdx]; + GrGlyph::PackedID glyphID = blob->fGlyphIDs[glyphIdx + info.fGlyphStartIndex]; if (regenerateTextureCoords) { // Upload the glyph only if needed @@ -771,7 +850,8 @@ public: // 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>(info.fVertices.begin()); + intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices); + vertex += info.fVertexStartIndex; vertex += vertexStride * glyphIdx * kVerticesPerGlyph; vertex += vertexStride - sizeof(SkIPoint16); @@ -779,7 +859,8 @@ public: } if (regenerateColors) { - intptr_t vertex = reinterpret_cast<intptr_t>(info.fVertices.begin()); + intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices); + vertex += info.fVertexStartIndex; vertex += vertexStride * glyphIdx * kVerticesPerGlyph + sizeof(SkPoint); this->regenerateColors(vertex, vertexStride, args.fColor); } @@ -797,8 +878,8 @@ public: } // now copy all vertices - int byteCount = info.fVertices.count(); - memcpy(currVertex, info.fVertices.begin(), byteCount); + size_t byteCount = info.fVertexEndIndex - info.fVertexStartIndex; + memcpy(currVertex, blob->fVertices + info.fVertexStartIndex, byteCount); currVertex += byteCount; } @@ -810,7 +891,7 @@ public: private: BitmapTextBatch(const Geometry& geometry, GrColor color, GrMaskFormat maskFormat, - GrBatchFontCache* fontCache) + int glyphCount, GrBatchFontCache* fontCache) : fMaskFormat(maskFormat) , fPixelConfig(fontCache->getPixelConfig(maskFormat)) , fFontCache(fontCache) { @@ -818,8 +899,7 @@ private: fGeoData.push_back(geometry); fBatch.fColor = color; fBatch.fViewMatrix = geometry.fBlob->fViewMatrix; - int numGlyphs = geometry.fBlob->fRuns[geometry.fRun].fInfos[maskFormat].fGlyphIDs.count(); - fBatch.fNumGlyphs = numGlyphs; + fBatch.fNumGlyphs = glyphCount; } void regenerateTextureCoords(GrGlyph* glyph, intptr_t vertex, size_t vertexStride) { @@ -932,27 +1012,6 @@ private: GrBatchFontCache* fFontCache; }; -void GrBitmapTextContextB::flushSubRun(GrDrawTarget* target, BitmapTextBlob* blob, int i, - GrPipelineBuilder* pipelineBuilder, GrMaskFormat format, - GrColor color, int paintAlpha) { - if (0 == blob->fRuns[i].fInfos[format].fGlyphIDs.count()) { - return; - } - - if (kARGB_GrMaskFormat == format) { - color = SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha, paintAlpha); - } - - BitmapTextBatch::Geometry geometry; - geometry.fBlob.reset(SkRef(blob)); - geometry.fRun = i; - geometry.fColor = color; - SkAutoTUnref<GrBatch> batch(BitmapTextBatch::Create(geometry, color, format, - fContext->getBatchFontCache())); - - target->drawBatch(pipelineBuilder, batch, &blob->fRuns[i].fVertexBounds); -} - void GrBitmapTextContextB::flush(GrDrawTarget* target, BitmapTextBlob* blob, GrRenderTarget* rt, const GrPaint& paint, const GrClip& clip, const SkMatrix& viewMatrix, int paintAlpha) { @@ -960,10 +1019,29 @@ void GrBitmapTextContextB::flush(GrDrawTarget* target, BitmapTextBlob* blob, GrR pipelineBuilder.setFromPaint(paint, rt, clip); GrColor color = paint.getColor(); - for (int i = 0; i < blob->fRuns.count(); i++) { - this->flushSubRun(target, blob, i, &pipelineBuilder, kA8_GrMaskFormat, color, paintAlpha); - this->flushSubRun(target, blob, i, &pipelineBuilder, kA565_GrMaskFormat, color, paintAlpha); - this->flushSubRun(target, blob, i, &pipelineBuilder, kARGB_GrMaskFormat, color, paintAlpha); + for (uint32_t run = 0; run < blob->fRunCount; run++) { + for (int subRun = 0; subRun < blob->fRuns[run].fSubRunInfo.count(); subRun++) { + PerSubRunInfo& info = blob->fRuns[run].fSubRunInfo[subRun]; + int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; + if (0 == glyphCount) { + continue; + } + + GrMaskFormat format = info.fMaskFormat; + if (kARGB_GrMaskFormat == format) { + color = SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha, paintAlpha); + } + + BitmapTextBatch::Geometry geometry; + geometry.fBlob.reset(SkRef(blob)); + geometry.fRun = run; + geometry.fSubRun = subRun; + geometry.fColor = color; + SkAutoTUnref<GrBatch> batch(BitmapTextBatch::Create(geometry, color, format, glyphCount, + fContext->getBatchFontCache())); + + target->drawBatch(&pipelineBuilder, batch, &blob->fRuns[run].fVertexBounds); + } } // Now flush big glyphs diff --git a/src/gpu/GrBitmapTextContext.h b/src/gpu/GrBitmapTextContext.h index 3bf3a941c6..1f8a82f35a 100644 --- a/src/gpu/GrBitmapTextContext.h +++ b/src/gpu/GrBitmapTextContext.h @@ -11,6 +11,8 @@ #include "GrTextContext.h" #include "GrGeometryProcessor.h" +#include "GrMemoryPool.h" +#include "SkDescriptor.h" #include "SkTHash.h" class GrBatchTextStrike; @@ -65,63 +67,108 @@ private: // this at a more fine grained level, but its not clear if this is worth it, as evictions // should be fairly rare. // One additional point, each run can contain glyphs with any of the three mask formats. - // We maintain separate arrays for each format type, and flush them separately. In practice - // most of the time a run will have the same format type + // We call these SubRuns. Because a subrun must be a contiguous range, we have to create + // a new subrun each time the mask format changes in a run. In theory, a run can have as + // many SubRuns as it has glyphs, ie if a run alternates between color emoji and A8. In + // practice, the vast majority of runs have only a single subrun. + struct Run { - Run() : fColor(GrColor_ILLEGAL) { fVertexBounds.setLargestInverted(); } - struct PerFormatInfo { - PerFormatInfo() : fAtlasGeneration(GrBatchAtlas::kInvalidAtlasGeneration) {} - SkTDArray<unsigned char> fVertices; - SkTDArray<GrGlyph::PackedID> fGlyphIDs; + Run() : fColor(GrColor_ILLEGAL), fInitialized(false) { + fVertexBounds.setLargestInverted(); + // We insert the first subrun to gurantee a run always has atleast one subrun. + // We do this to simplify things when we 'hand off' data from one subrun to the + // next + fSubRunInfo.push_back(); + } + struct SubRunInfo { + SubRunInfo() + : fAtlasGeneration(GrBatchAtlas::kInvalidAtlasGeneration) + , fGlyphStartIndex(0) + , fGlyphEndIndex(0) + , fVertexStartIndex(0) + , fVertexEndIndex(0) {} + GrMaskFormat fMaskFormat; uint64_t fAtlasGeneration; + uint32_t fGlyphStartIndex; + uint32_t fGlyphEndIndex; + size_t fVertexStartIndex; + size_t fVertexEndIndex; }; - SkAutoTUnref<const SkData> fDescriptor; + SkSTArray<1, SubRunInfo, true> fSubRunInfo; + SkAutoDescriptor fDescriptor; SkAutoTUnref<SkTypeface> fTypeface; - PerFormatInfo fInfos[kMaskFormatCount]; SkRect fVertexBounds; GrColor fColor; + bool fInitialized; }; - SkSTArray<1, Run, true> fRuns; + struct BigGlyph { BigGlyph(const SkPath& path, int vx, int vy) : fPath(path), fVx(vx), fVy(vy) {} SkPath fPath; int fVx; int fVy; }; + SkTArray<BigGlyph> fBigGlyphs; - SkTextBlob* fBlob; SkMatrix fViewMatrix; SkScalar fX; SkScalar fY; SkPaint::Style fStyle; + uint32_t fRunCount; + + // all glyph / vertex offsets are into these pools. + unsigned char* fVertices; + GrGlyph::PackedID* fGlyphIDs; + Run* fRuns; static uint32_t Hash(const uint32_t& key) { return SkChecksum::Mix(key); } + + void operator delete(void* p) { sk_free(p); } + void* operator new(size_t) { + SkFAIL("All blobs are created by placement new."); + return sk_malloc_throw(0); + } + + void* operator new(size_t, void* p) { return p; } + void operator delete(void* target, void* placement) { + ::operator delete(target, placement); + } }; + typedef BitmapTextBlob::Run Run; + typedef Run::SubRunInfo PerSubRunInfo; + + BitmapTextBlob* CreateBlob(int glyphCount, int runCount); + void appendGlyph(BitmapTextBlob*, int runIndex, GrGlyph::PackedID, int left, int top, GrFontScaler*, const SkIRect& clipRect); - void flushSubRun(GrDrawTarget*, BitmapTextBlob*, int i, GrPipelineBuilder*, GrMaskFormat, - GrColor color, int paintAlpha); void flush(GrDrawTarget*, BitmapTextBlob*, GrRenderTarget*, const GrPaint&, const GrClip&, const SkMatrix& viewMatrix, int paintAlpha); - void internalDrawText(BitmapTextBlob*, int runIndex, const SkPaint&, + void internalDrawText(BitmapTextBlob*, int runIndex, SkGlyphCache*, const SkPaint&, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkIRect& clipRect); - void internalDrawPosText(BitmapTextBlob*, int runIndex, const SkPaint&, + void internalDrawPosText(BitmapTextBlob*, int runIndex, SkGlyphCache*, const SkPaint&, const SkMatrix& viewMatrix, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset, const SkIRect& clipRect); + // sets up the descriptor on the blob and returns a detached cache. Client must attach + inline SkGlyphCache* setupCache(Run*, const SkPaint&, const SkMatrix& viewMatrix); static inline bool MustRegenerateBlob(const BitmapTextBlob&, const SkPaint&, const SkMatrix& viewMatrix, SkScalar x, SkScalar y); void regenerateTextBlob(BitmapTextBlob* bmp, const SkPaint& skPaint, const SkMatrix& viewMatrix, const SkTextBlob* blob, SkScalar x, SkScalar y, SkDrawFilter* drawFilter, const SkIRect& clipRect); + // TODO this currently only uses the public interface of SkTextBlob, however, I may need to add + // functionality to it while looping over the runs so I'm putting this here for the time being. + // If this lands in Chrome without changes, move it to SkTextBlob. + static inline void BlobGlyphCount(int* glyphCount, int* runCount, const SkTextBlob*); + GrBatchTextStrike* fCurrStrike; // TODO use real cache |