aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--samplecode/SampleChineseFling.cpp43
-rw-r--r--src/gpu/GrDrawOpAtlas.cpp62
-rw-r--r--src/gpu/GrDrawOpAtlas.h8
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;