aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Brian Salomon <bsalomon@google.com>2017-11-06 10:36:57 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-11-06 16:06:09 +0000
commit9f545bc18a1fdff64d40104028c6d8449e660a6e (patch)
tree3f2b5eb9124f53d4fd9610445ceb5d374ae7d424
parent97f0bc6a1a0d14fd7b9041c39449966535f9f431 (diff)
Modify fontcache GM to actually spill atlas.
Adds an option to GrDrawOpAtlas to disable multitexturing. Adds option to GrContextOptions to disable multitexturing for glyph atlases. Change-Id: If413ab7061538fa0e75628d252be4fd14215b6ba Reviewed-on: https://skia-review.googlesource.com/67802 Reviewed-by: Jim Van Verth <jvanverth@google.com> Commit-Queue: Brian Salomon <bsalomon@google.com>
-rw-r--r--gm/fontcache.cpp105
-rw-r--r--include/gpu/GrContextOptions.h6
-rw-r--r--src/gpu/GrContext.cpp9
-rw-r--r--src/gpu/GrDrawOpAtlas.cpp20
-rw-r--r--src/gpu/GrDrawOpAtlas.h31
-rw-r--r--src/gpu/ops/GrSmallPathRenderer.cpp9
-rw-r--r--src/gpu/text/GrAtlasGlyphCache.cpp28
-rw-r--r--src/gpu/text/GrAtlasGlyphCache.h3
8 files changed, 138 insertions, 73 deletions
diff --git a/gm/fontcache.cpp b/gm/fontcache.cpp
index a8c5b768c3..b93cc3f031 100644
--- a/gm/fontcache.cpp
+++ b/gm/fontcache.cpp
@@ -5,11 +5,14 @@
* found in the LICENSE file.
*/
-#include "gm.h"
-#include "sk_tool_utils.h"
+#include "GrContext.h"
+#include "GrContextOptions.h"
#include "SkCanvas.h"
#include "SkGraphics.h"
+#include "SkImage.h"
#include "SkTypeface.h"
+#include "gm.h"
+#include "sk_tool_utils.h"
// GM to stress the GPU font cache
@@ -21,58 +24,94 @@ static SkScalar draw_string(SkCanvas* canvas, const SkString& text, SkScalar x,
class FontCacheGM : public skiagm::GM {
public:
- FontCacheGM() {}
+ FontCacheGM() { this->setBGColor(SK_ColorLTGRAY); }
+
+ void modifyGrContextOptions(GrContextOptions* options) override {
+ options->fGlyphCacheTextureMaximumBytes = 0;
+ options->fAllowMultipleGlyphCacheTextures = GrContextOptions::Enable::kNo;
+ }
protected:
SkString onShortName() override {
return SkString("fontcache");
}
- SkISize onISize() override {
- return SkISize::Make(1280, 640);
- }
+ SkISize onISize() override { return SkISize::Make(kSize, kSize); }
void onOnceBeforeDraw() override {
fTypefaces[0] = sk_tool_utils::create_portable_typeface("serif", SkFontStyle::Italic());
fTypefaces[1] = sk_tool_utils::create_portable_typeface("sans-serif",SkFontStyle::Italic());
+ fTypefaces[2] = sk_tool_utils::create_portable_typeface("serif", SkFontStyle::Normal());
+ fTypefaces[3] =
+ sk_tool_utils::create_portable_typeface("sans-serif", SkFontStyle::Normal());
+ fTypefaces[4] = sk_tool_utils::create_portable_typeface("serif", SkFontStyle::Bold());
+ fTypefaces[5] = sk_tool_utils::create_portable_typeface("sans-serif", SkFontStyle::Bold());
}
void onDraw(SkCanvas* canvas) override {
+ canvas->clear(SK_ColorLTGRAY);
+ this->drawText(canvas);
+ // Debugging tool for GPU.
+ static const bool kShowAtlas = false;
+ if (kShowAtlas) {
+ if (auto ctx = canvas->getGrContext()) {
+ auto img = ctx->getFontAtlasImage_ForTesting(kA8_GrMaskFormat);
+ canvas->drawImage(img, 0, 0);
+ }
+ }
+ }
+
+private:
+ void drawText(SkCanvas* canvas) {
+ static const int kSizes[] = {8, 9, 10, 11, 12, 13, 18, 20, 25};
+
+ static const SkString kTexts[] = {SkString("ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
+ SkString("abcdefghijklmnopqrstuvwxyz"),
+ SkString("0123456789"),
+ SkString("!@#$%^&*()<>[]{}")};
SkPaint paint;
paint.setAntiAlias(true);
- paint.setLCDRenderText(true);
+ paint.setLCDRenderText(false);
paint.setSubpixelText(true);
- paint.setTypeface(fTypefaces[0]);
- paint.setTextSize(192);
-
- // Make sure the nul character does not cause problems.
- paint.measureText("\0", 1);
-
- SkScalar x = 20;
- SkScalar y = 128;
- SkString text("ABCDEFGHIJ");
- draw_string(canvas, text, x, y, paint);
- y += 100;
- SkString text2("KLMNOPQRS");
- draw_string(canvas, text2, x, y, paint);
- y += 100;
- SkString text3("TUVWXYZ012");
- draw_string(canvas, text3, x, y, paint);
- y += 100;
- paint.setTypeface(fTypefaces[1]);
- draw_string(canvas, text, x, y, paint);
- y += 100;
- draw_string(canvas, text2, x, y, paint);
- y += 100;
- draw_string(canvas, text3, x, y, paint);
- y += 100;
+
+ static const SkScalar kSubPixelInc = 1 / 2.f;
+ SkScalar x = 0;
+ SkScalar y = 10;
+ SkScalar subpixelX = 0;
+ SkScalar subpixelY = 0;
+ bool offsetX = true;
+
+ do {
+ for (auto s : kSizes) {
+ auto size = 2 * s;
+ paint.setTextSize(size);
+ for (const auto& typeface : fTypefaces) {
+ paint.setTypeface(typeface);
+ for (const auto& text : kTexts) {
+ x = size + draw_string(canvas, text, x + subpixelX, y + subpixelY, paint);
+ x = SkScalarCeilToScalar(x);
+ if (x + 100 > kSize) {
+ x = 0;
+ y += SkScalarCeilToScalar(size + 3);
+ if (y > kSize) {
+ return;
+ }
+ }
+ }
+ }
+ (offsetX ? subpixelX : subpixelY) += kSubPixelInc;
+ offsetX = !offsetX;
+ }
+ } while (true);
}
-private:
- sk_sp<SkTypeface> fTypefaces[2];
+ static constexpr SkScalar kSize = 1280;
+
+ sk_sp<SkTypeface> fTypefaces[6];
typedef GM INHERITED;
};
+constexpr SkScalar FontCacheGM::kSize;
//////////////////////////////////////////////////////////////////////////////
diff --git a/include/gpu/GrContextOptions.h b/include/gpu/GrContextOptions.h
index 7aa85e0ed3..a3c914aa3b 100644
--- a/include/gpu/GrContextOptions.h
+++ b/include/gpu/GrContextOptions.h
@@ -114,6 +114,12 @@ struct GrContextOptions {
float fGlyphCacheTextureMaximumBytes = 2048 * 1024 * 4;
/**
+ * Can the glyph atlas use multiple textures. If allowed, the each texture's size is bound by
+ * fGlypheCacheTextureMaximumBytes.
+ */
+ Enable fAllowMultipleGlyphCacheTextures = Enable::kDefault;
+
+ /**
* Bugs on certain drivers cause stencil buffers to leak. This flag causes Skia to avoid
* allocating stencil buffers and use alternate rasterization paths, avoiding the leak.
*/
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 2146858f79..d3194be8f2 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -204,7 +204,14 @@ bool GrContext::init(const GrContextOptions& options) {
}
fDrawingManager.reset(new GrDrawingManager(this, prcOptions, &fSingleOwner));
- fAtlasGlyphCache = new GrAtlasGlyphCache(this, options.fGlyphCacheTextureMaximumBytes);
+ GrDrawOpAtlas::AllowMultitexturing allowMultitexturing;
+ if (options.fAllowMultipleGlyphCacheTextures == GrContextOptions::Enable::kNo) {
+ allowMultitexturing = GrDrawOpAtlas::AllowMultitexturing::kNo;
+ } else {
+ allowMultitexturing = GrDrawOpAtlas::AllowMultitexturing::kYes;
+ }
+ fAtlasGlyphCache = new GrAtlasGlyphCache(this, options.fGlyphCacheTextureMaximumBytes,
+ allowMultitexturing);
this->contextPriv().addOnFlushCallbackObject(fAtlasGlyphCache);
fTextBlobCache.reset(new GrTextBlobCache(TextBlobCacheOverBudgetCB, this));
diff --git a/src/gpu/GrDrawOpAtlas.cpp b/src/gpu/GrDrawOpAtlas.cpp
index 8d812857a6..c0358b79ea 100644
--- a/src/gpu/GrDrawOpAtlas.cpp
+++ b/src/gpu/GrDrawOpAtlas.cpp
@@ -14,13 +14,12 @@
#include "GrTexture.h"
#include "GrTracing.h"
-std::unique_ptr<GrDrawOpAtlas> GrDrawOpAtlas::Make(GrContext* ctx, GrPixelConfig config,
- int width, int height,
- int numPlotsX, int numPlotsY,
- GrDrawOpAtlas::EvictionFunc func,
- void* data) {
- std::unique_ptr<GrDrawOpAtlas> atlas(
- new GrDrawOpAtlas(ctx, config, width, height, numPlotsX, numPlotsY));
+std::unique_ptr<GrDrawOpAtlas> GrDrawOpAtlas::Make(GrContext* ctx, GrPixelConfig config, int width,
+ int height, int numPlotsX, int numPlotsY,
+ AllowMultitexturing allowMultitexturing,
+ GrDrawOpAtlas::EvictionFunc func, void* data) {
+ std::unique_ptr<GrDrawOpAtlas> atlas(new GrDrawOpAtlas(ctx, config, width, height, numPlotsX,
+ numPlotsY, allowMultitexturing));
if (!atlas->getProxies()[0]) {
return nullptr;
}
@@ -147,13 +146,14 @@ void GrDrawOpAtlas::Plot::resetRects() {
///////////////////////////////////////////////////////////////////////////////
GrDrawOpAtlas::GrDrawOpAtlas(GrContext* context, GrPixelConfig config, int width, int height,
- int numPlotsX, int numPlotsY)
+ int numPlotsX, int numPlotsY, AllowMultitexturing allowMultitexturing)
: fContext(context)
, fPixelConfig(config)
, fTextureWidth(width)
, fTextureHeight(height)
, fAtlasGeneration(kInvalidAtlasGeneration + 1)
, fPrevFlushToken(GrDeferredUploadToken::AlreadyFlushedToken())
+ , fAllowMultitexturing(allowMultitexturing)
, fNumPages(0) {
fPlotWidth = fTextureWidth / numPlotsX;
fPlotHeight = fTextureHeight / numPlotsY;
@@ -242,7 +242,7 @@ bool GrDrawOpAtlas::addToAtlas(AtlasID* id, GrDeferredUploadTarget* target, int
for (unsigned int pageIdx = 0; pageIdx < fNumPages; ++pageIdx) {
Plot* plot = fPages[pageIdx].fPlotList.tail();
SkASSERT(plot);
- if ((fNumPages == kMaxPages && plot->lastUseToken() < target->nextTokenToFlush()) ||
+ if ((fNumPages == this->maxPages() && plot->lastUseToken() < target->nextTokenToFlush()) ||
plot->flushesSinceLastUsed() >= kRecentlyUsedCount) {
this->processEvictionAndResetRects(plot);
SkASSERT(GrBytesPerPixel(fProxies[pageIdx]->config()) == plot->bpp());
@@ -448,7 +448,7 @@ void GrDrawOpAtlas::compact(GrDeferredUploadToken startTokenForNextFlush) {
}
bool GrDrawOpAtlas::createNewPage() {
- if (fNumPages == kMaxPages) {
+ if (fNumPages == this->maxPages()) {
return false;
}
diff --git a/src/gpu/GrDrawOpAtlas.h b/src/gpu/GrDrawOpAtlas.h
index 91a88ecdba..edab2cbd24 100644
--- a/src/gpu/GrDrawOpAtlas.h
+++ b/src/gpu/GrDrawOpAtlas.h
@@ -51,7 +51,13 @@ struct GrDrawOpAtlasConfig {
* and passes in the given GrDrawUploadToken.
*/
class GrDrawOpAtlas {
+private:
+ static constexpr auto kMaxMultitexturePages = 4;
+
public:
+ /** Is the atlas allowed to use more than one texture? */
+ enum class AllowMultitexturing : bool { kNo, kYes };
+
/**
* An AtlasID is an opaque handle which callers can use to determine if the atlas contains
* a specific piece of data.
@@ -77,15 +83,16 @@ public:
* direction
* @param numPlotsY The number of plots the atlas should be broken up into in the Y
* direction
+ * @param allowMultitexturing Can the atlas use more than one texture.
* @param func An eviction function which will be called whenever the atlas has to
* evict data
- * @param data User supplied data which will be passed into func whenver an
+ * @param data User supplied data which will be passed into func whenever an
* eviction occurs
* @return An initialized GrDrawOpAtlas, or nullptr if creation fails
*/
- static std::unique_ptr<GrDrawOpAtlas> Make(GrContext*, GrPixelConfig,
- int width, int height,
+ static std::unique_ptr<GrDrawOpAtlas> Make(GrContext*, GrPixelConfig, int width, int height,
int numPlotsX, int numPlotsY,
+ AllowMultitexturing allowMultitexturing,
GrDrawOpAtlas::EvictionFunc func, void* data);
/**
@@ -134,7 +141,6 @@ public:
data->fData = userData;
}
- static constexpr auto kMaxPages = 4;
uint32_t pageCount() { return fNumPages; }
/**
@@ -186,7 +192,7 @@ public:
static constexpr int kMinItems = 4;
static constexpr int kMaxPlots = 32;
SkSTArray<kMinItems, PlotData, true> fPlotsToUpdate;
- uint32_t fPlotAlreadyUpdated[kMaxPages];
+ uint32_t fPlotAlreadyUpdated[kMaxMultitexturePages];
friend class GrDrawOpAtlas;
};
@@ -217,8 +223,12 @@ public:
}
private:
- GrDrawOpAtlas(GrContext*, GrPixelConfig config, int width, int height,
- int numPlotsX, int numPlotsY);
+ uint32_t maxPages() const {
+ return AllowMultitexturing::kYes == fAllowMultitexturing ? kMaxMultitexturePages : 1;
+ }
+
+ GrDrawOpAtlas(GrContext*, GrPixelConfig config, int width, int height, int numPlotsX,
+ int numPlotsY, AllowMultitexturing allowMultitexturing);
/**
* The backing GrTexture for a GrDrawOpAtlas is broken into a spatial grid of Plots. The Plots
@@ -282,7 +292,7 @@ private:
static GrDrawOpAtlas::AtlasID CreateId(uint32_t pageIdx, uint32_t plotIdx,
uint64_t generation) {
SkASSERT(pageIdx < (1 << 8));
- SkASSERT(pageIdx < kMaxPages);
+ SkASSERT(pageIdx < kMaxMultitexturePages);
SkASSERT(plotIdx < (1 << 8));
SkASSERT(generation < ((uint64_t)1 << 48));
return generation << 16 | plotIdx << 8 | pageIdx;
@@ -376,8 +386,9 @@ private:
PlotList fPlotList;
};
// proxies kept separate to make it easier to pass them up to client
- sk_sp<GrTextureProxy> fProxies[kMaxPages];
- Page fPages[kMaxPages];
+ sk_sp<GrTextureProxy> fProxies[kMaxMultitexturePages];
+ Page fPages[kMaxMultitexturePages];
+ AllowMultitexturing fAllowMultitexturing;
uint32_t fNumPages;
};
diff --git a/src/gpu/ops/GrSmallPathRenderer.cpp b/src/gpu/ops/GrSmallPathRenderer.cpp
index d3084981f8..4f4dcc1f3b 100644
--- a/src/gpu/ops/GrSmallPathRenderer.cpp
+++ b/src/gpu/ops/GrSmallPathRenderer.cpp
@@ -181,10 +181,9 @@ public:
fHelper.visitProxies(func);
const sk_sp<GrTextureProxy>* proxies = fAtlas->getProxies();
- for (int i = 0; i < GrDrawOpAtlas::kMaxPages; ++i) {
- if (proxies[i].get()) {
- func(proxies[i].get());
- }
+ for (uint32_t i = 0; i < fAtlas->pageCount(); ++i) {
+ SkASSERT(proxies[i]);
+ func(proxies[i].get());
}
}
@@ -793,6 +792,7 @@ bool GrSmallPathRenderer::onDrawPath(const DrawPathArgs& args) {
kAlpha_8_GrPixelConfig,
ATLAS_TEXTURE_WIDTH, ATLAS_TEXTURE_HEIGHT,
NUM_PLOTS_X, NUM_PLOTS_Y,
+ GrDrawOpAtlas::AllowMultitexturing::kYes,
&GrSmallPathRenderer::HandleEviction,
(void*)this);
if (!fAtlas) {
@@ -861,6 +861,7 @@ GR_DRAW_OP_TEST_DEFINE(SmallPathOp) {
gTestStruct.fAtlas = GrDrawOpAtlas::Make(context, kAlpha_8_GrPixelConfig,
ATLAS_TEXTURE_WIDTH, ATLAS_TEXTURE_HEIGHT,
NUM_PLOTS_X, NUM_PLOTS_Y,
+ GrDrawOpAtlas::AllowMultitexturing::kYes,
&PathTestStruct::HandleEviction,
(void*)&gTestStruct);
}
diff --git a/src/gpu/text/GrAtlasGlyphCache.cpp b/src/gpu/text/GrAtlasGlyphCache.cpp
index 25575bef52..80f4314b91 100644
--- a/src/gpu/text/GrAtlasGlyphCache.cpp
+++ b/src/gpu/text/GrAtlasGlyphCache.cpp
@@ -25,9 +25,9 @@ bool GrAtlasGlyphCache::initAtlas(GrMaskFormat format) {
int numPlotsX = fAtlasConfigs[index].numPlotsX();
int numPlotsY = fAtlasConfigs[index].numPlotsY();
- fAtlases[index] = GrDrawOpAtlas::Make(
- fContext, config, width, height, numPlotsX, numPlotsY,
- &GrAtlasGlyphCache::HandleEviction, (void*)this);
+ fAtlases[index] = GrDrawOpAtlas::Make(fContext, config, width, height, numPlotsX, numPlotsY,
+ fAllowMultitexturing,
+ &GrAtlasGlyphCache::HandleEviction, (void*)this);
if (!fAtlases[index]) {
return false;
}
@@ -35,11 +35,12 @@ bool GrAtlasGlyphCache::initAtlas(GrMaskFormat format) {
return true;
}
-GrAtlasGlyphCache::GrAtlasGlyphCache(GrContext* context, float maxTextureBytes)
- : fContext(context), fPreserveStrike(nullptr) {
- // Calculate RGBA size. Must be between 1024 x 512 and MaxTextureSize x MaxTextureSize / 2
+GrAtlasGlyphCache::GrAtlasGlyphCache(GrContext* context, float maxTextureBytes,
+ GrDrawOpAtlas::AllowMultitexturing allowMultitexturing)
+ : fContext(context), fAllowMultitexturing(allowMultitexturing), fPreserveStrike(nullptr) {
+ // Calculate RGBA size. Must be between 512 x 256 and MaxTextureSize x MaxTextureSize / 2
int log2MaxTextureSize = SkPrevLog2(context->caps()->maxTextureSize());
- int log2MaxDim = 10;
+ int log2MaxDim = 9;
for (; log2MaxDim <= log2MaxTextureSize; ++log2MaxDim) {
int maxDim = 1 << log2MaxDim;
int minDim = 1 << (log2MaxDim - 1);
@@ -177,17 +178,16 @@ void GrAtlasGlyphCache::dump() const {
for (int i = 0; i < kMaskFormatCount; ++i) {
if (fAtlases[i]) {
const sk_sp<GrTextureProxy>* proxies = fAtlases[i]->getProxies();
- for (int pageIdx = 0; pageIdx < GrDrawOpAtlas::kMaxPages; ++pageIdx) {
- if (proxies[pageIdx]) {
- SkString filename;
+ for (uint32_t pageIdx = 0; pageIdx < fAtlases[i]->pageCount(); ++pageIdx) {
+ SkASSERT(proxies[pageIdx]);
+ SkString filename;
#ifdef SK_BUILD_FOR_ANDROID
- filename.printf("/sdcard/fontcache_%d%d%d.png", gDumpCount, i, pageIdx);
+ filename.printf("/sdcard/fontcache_%d%d%d.png", gDumpCount, i, pageIdx);
#else
- filename.printf("fontcache_%d%d%d.png", gDumpCount, i, pageIdx);
+ filename.printf("fontcache_%d%d%d.png", gDumpCount, i, pageIdx);
#endif
- save_pixels(fContext, proxies[pageIdx].get(), filename.c_str());
- }
+ save_pixels(fContext, proxies[pageIdx].get(), filename.c_str());
}
}
}
diff --git a/src/gpu/text/GrAtlasGlyphCache.h b/src/gpu/text/GrAtlasGlyphCache.h
index 20bc32a408..a75ef53b09 100644
--- a/src/gpu/text/GrAtlasGlyphCache.h
+++ b/src/gpu/text/GrAtlasGlyphCache.h
@@ -111,7 +111,7 @@ private:
*/
class GrAtlasGlyphCache : public GrOnFlushCallbackObject {
public:
- GrAtlasGlyphCache(GrContext*, float maxTextureBytes);
+ GrAtlasGlyphCache(GrContext*, float maxTextureBytes, GrDrawOpAtlas::AllowMultitexturing);
~GrAtlasGlyphCache() override;
// The user of the cache may hold a long-lived ref to the returned strike. However, actions by
// another client of the cache may cause the strike to be purged while it is still reffed.
@@ -256,6 +256,7 @@ private:
using StrikeHash = SkTDynamicHash<GrAtlasTextStrike, SkDescriptor>;
GrContext* fContext;
StrikeHash fCache;
+ GrDrawOpAtlas::AllowMultitexturing fAllowMultitexturing;
std::unique_ptr<GrDrawOpAtlas> fAtlases[kMaskFormatCount];
GrAtlasTextStrike* fPreserveStrike;
GrDrawOpAtlasConfig fAtlasConfigs[kMaskFormatCount];