diff options
-rw-r--r-- | samplecode/SampleChineseFling.cpp | 43 | ||||
-rw-r--r-- | src/gpu/GrDrawOpAtlas.cpp | 62 | ||||
-rw-r--r-- | src/gpu/GrDrawOpAtlas.h | 8 |
3 files changed, 84 insertions, 29 deletions
diff --git a/samplecode/SampleChineseFling.cpp b/samplecode/SampleChineseFling.cpp index 036f834931..536f2c2abd 100644 --- a/samplecode/SampleChineseFling.cpp +++ b/samplecode/SampleChineseFling.cpp @@ -25,13 +25,6 @@ static void make_paint(SkPaint* paint, sk_sp<SkTypeface> typeface) { paint->setTextEncoding(SkPaint::kUTF32_TextEncoding); } -static void get_unicode_row(SkUnichar base, SkUnichar glyphs[16]) { - for (int i = 0x0; i <= 0xF; ++i) { - glyphs[i] = base; - glyphs[i] |= i; - } -} - static sk_sp<SkTypeface> chinese_typeface() { #ifdef SK_BUILD_FOR_ANDROID return MakeResourceAsTypeface("/fonts/NotoSansCJK-Regular.ttc"); @@ -50,7 +43,7 @@ static sk_sp<SkTypeface> chinese_typeface() { class ChineseFlingView : public SampleView { public: - ChineseFlingView() {} + ChineseFlingView() : fBlobs(kNumBlobs) {} protected: bool onQuery(SkEvent* evt) override { @@ -72,19 +65,28 @@ protected: SkPaint paint; make_paint(&paint, fTypeface); + // draw a consistent run of the 'words' - one word per line + int index = fIndex; for (SkScalar y = 0.0f; y < 1024.0f; ) { - int index = fRand.nextRangeU(0, fBlobs.count()-1); y += -fMetrics.fAscent; canvas->drawTextBlob(fBlobs[index], 0, y, paint); y += fMetrics.fDescent + fMetrics.fLeading; + ++index; + index %= fBlobs.count(); } + // now "fling" a random amount + fIndex += fRand.nextRangeU(5, 20); + fIndex %= fBlobs.count(); this->inval(nullptr); } private: + static constexpr auto kNumBlobs = 200; + static constexpr auto kWordLength = 16; + void init() { fTypeface = chinese_typeface(); @@ -93,19 +95,25 @@ private: paint.getFontMetrics(&fMetrics); - SkUnichar glyphs[16]; - - for (int32_t i = 0x4F00; i < 0x9FA0; i += 0x10) { - - get_unicode_row(i, glyphs); + SkUnichar glyphs[kWordLength]; + for (int32_t i = 0; i < kNumBlobs; ++i) { + this->createRandomWord(glyphs); SkTextBlobBuilder builder; - - sk_tool_utils::add_to_text_blob_w_len(&builder, (const char*) glyphs, 16*4, paint, - 0, 0); + sk_tool_utils::add_to_text_blob_w_len(&builder, (const char*) glyphs, kWordLength*4, + paint, 0, 0); fBlobs.emplace_back(builder.make()); } + + fIndex = 0; + } + + // Construct a random kWordLength character 'word' drawing from the full Chinese set + void createRandomWord(SkUnichar glyphs[kWordLength]) { + for (int i = 0; i < kWordLength; ++i) { + glyphs[i] = fRand.nextRangeU(0x4F00, 0x9FA0); + } } bool fInitialized = false; @@ -113,6 +121,7 @@ private: SkPaint::FontMetrics fMetrics; SkTArray<sk_sp<SkTextBlob>> fBlobs; SkRandom fRand; + int fIndex; typedef SkView INHERITED; }; diff --git a/src/gpu/GrDrawOpAtlas.cpp b/src/gpu/GrDrawOpAtlas.cpp index 233a7cf12c..0d195635b9 100644 --- a/src/gpu/GrDrawOpAtlas.cpp +++ b/src/gpu/GrDrawOpAtlas.cpp @@ -29,6 +29,9 @@ std::unique_ptr<GrDrawOpAtlas> GrDrawOpAtlas::Make(GrContext* ctx, GrPixelConfig return atlas; } +#ifdef DUMP_ATLAS_DATA +static bool gDumpAtlasData = false; +#endif //////////////////////////////////////////////////////////////////////////////// @@ -129,6 +132,8 @@ void GrDrawOpAtlas::Plot::resetRects() { fGenID++; fID = CreateId(fPageIndex, fPlotIndex, fGenID); + fLastUpload = GrDrawOpUploadToken::AlreadyFlushedToken(); + fLastUse = GrDrawOpUploadToken::AlreadyFlushedToken(); // zero out the plot if (fData) { @@ -162,10 +167,11 @@ GrDrawOpAtlas::GrDrawOpAtlas(GrContext* context, GrPixelConfig config, int width this->createNewPage(); } -void GrDrawOpAtlas::processEviction(AtlasID id) { +inline void GrDrawOpAtlas::processEviction(AtlasID id) { for (int i = 0; i < fEvictionCallbacks.count(); i++) { (*fEvictionCallbacks[i].fFunc)(id, fEvictionCallbacks[i].fData); } + ++fAtlasGeneration; } inline bool GrDrawOpAtlas::updatePlot(GrDrawOp::Target* target, AtlasID* id, Plot* plot) { @@ -240,15 +246,13 @@ bool GrDrawOpAtlas::addToAtlas(AtlasID* id, GrDrawOp::Target* target, int width, SkASSERT(plot); if ((fNumPages == kMaxPages && target->hasDrawBeenFlushed(plot->lastUseToken())) || plot->flushesSinceLastUsed() >= kRecentlyUsedCount) { - this->processEviction(plot->id()); - plot->resetRects(); + this->processEvictionAndResetRects(plot); SkASSERT(GrBytesPerPixel(fProxies[pageIdx]->config()) == plot->bpp()); SkDEBUGCODE(bool verify = )plot->addSubImage(width, height, image, loc); SkASSERT(verify); if (!this->updatePlot(target, id, plot)) { return false; } - fAtlasGeneration++; return true; } } @@ -319,7 +323,6 @@ bool GrDrawOpAtlas::addToAtlas(AtlasID* id, GrDrawOp::Target* target, int width, *id = newPlot->id(); - fAtlasGeneration++; return true; } @@ -356,6 +359,11 @@ void GrDrawOpAtlas::compact(GrDrawOpUploadToken startTokenForNextFlush) { // For all plots but the last one, update number of flushes since used, and check to see // if there are any in the first pages that the last page can safely upload to. for (uint32_t pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex) { +#ifdef DUMP_ATLAS_DATA + if (gDumpAtlasData) { + SkDebugf("page %d: ", pageIndex); + } +#endif plotIter.init(fPages[pageIndex].fPlotList, PlotList::Iter::kHead_IterStart); while (Plot* plot = plotIter.get()) { // Update number of flushes since plot was last used @@ -366,6 +374,11 @@ void GrDrawOpAtlas::compact(GrDrawOpUploadToken startTokenForNextFlush) { plot->incFlushesSinceLastUsed(); } +#ifdef DUMP_ATLAS_DATA + if (gDumpAtlasData) { + SkDebugf("%d ", plot->flushesSinceLastUsed()); + } +#endif // Count plots we can potentially upload to in all pages except the last one // (the potential compactee). if (plot->flushesSinceLastUsed() > kRecentlyUsedCount) { @@ -374,6 +387,11 @@ void GrDrawOpAtlas::compact(GrDrawOpUploadToken startTokenForNextFlush) { plotIter.next(); } +#ifdef DUMP_ATLAS_DATA + if (gDumpAtlasData) { + SkDebugf("\n"); + } +#endif } // Count recently used plots in the last page and evict them if there's available space @@ -381,12 +399,22 @@ void GrDrawOpAtlas::compact(GrDrawOpUploadToken startTokenForNextFlush) { // clear out usage of this page unless we have a large need. plotIter.init(fPages[lastPageIndex].fPlotList, PlotList::Iter::kHead_IterStart); int usedPlots = 0; +#ifdef DUMP_ATLAS_DATA + if (gDumpAtlasData) { + SkDebugf("page %d: ", lastPageIndex); + } +#endif while (Plot* plot = plotIter.get()) { // Update number of flushes since plot was last used if (!plot->lastUseToken().inInterval(fPrevFlushToken, startTokenForNextFlush)) { plot->incFlushesSinceLastUsed(); } +#ifdef DUMP_ATLAS_DATA + if (gDumpAtlasData) { + SkDebugf("%d ", plot->flushesSinceLastUsed()); + } +#endif // If this plot was used recently if (plot->flushesSinceLastUsed() <= kRecentlyUsedCount) { usedPlots++; @@ -394,20 +422,27 @@ void GrDrawOpAtlas::compact(GrDrawOpUploadToken startTokenForNextFlush) { // We need to be somewhat harsh here so that one plot that is consistently in use // doesn't end up locking the page in memory. if (availablePlots) { - this->processEviction(plot->id()); - plot->resetRects(); + this->processEvictionAndResetRects(plot); --availablePlots; } - } else { + } else if (plot->lastUseToken() != GrDrawOpUploadToken::AlreadyFlushedToken()) { // otherwise if aged out just evict it. - this->processEviction(plot->id()); - plot->resetRects(); + this->processEvictionAndResetRects(plot); } plotIter.next(); } - +#ifdef DUMP_ATLAS_DATA + if (gDumpAtlasData) { + SkDebugf("\n"); + } +#endif // If none of the plots in the last page have been used recently, delete it. if (!usedPlots) { +#ifdef DUMP_ATLAS_DATA + if (gDumpAtlasData) { + SkDebugf("delete %d\n", fNumPages-1); + } +#endif this->deleteLastPage(); } } @@ -464,6 +499,11 @@ bool GrDrawOpAtlas::createNewPage() { } } +#ifdef DUMP_ATLAS_DATA + if (gDumpAtlasData) { + SkDebugf("created %d\n", fNumPages); + } +#endif fNumPages++; return true; } diff --git a/src/gpu/GrDrawOpAtlas.h b/src/gpu/GrDrawOpAtlas.h index 2031d2e60b..647e6a58b9 100644 --- a/src/gpu/GrDrawOpAtlas.h +++ b/src/gpu/GrDrawOpAtlas.h @@ -195,6 +195,8 @@ public: int count = updater.fPlotsToUpdate.count(); for (int i = 0; i < count; i++) { const BulkUseTokenUpdater::PlotData& pd = updater.fPlotsToUpdate[i]; + // it's possible we've added a plot to the updater and subsequently the plot's page + // was deleted -- so we check to prevent a crash if (pd.fPageIndex < fNumPages) { Plot* plot = fPages[pd.fPageIndex].fPlotArray[pd.fPlotIndex].get(); this->makeMRU(plot, pd.fPageIndex); @@ -342,7 +344,11 @@ private: bool createNewPage(); void deleteLastPage(); - inline void processEviction(AtlasID); + void processEviction(AtlasID); + inline void processEvictionAndResetRects(Plot* plot) { + this->processEviction(plot->id()); + plot->resetRects(); + } GrContext* fContext; GrPixelConfig fPixelConfig; |