aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Jim Van Verth <jvanverth@google.com>2017-09-15 12:14:26 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-09-15 16:34:34 +0000
commit03168b8a62a0d3d14b7a0d14642df4d82203b87c (patch)
tree011df89efc1f6416ec08f6b1d6de173ff3000b1b
parenta4083c97d48e8a4f88e2797d7363f141e3d42553 (diff)
Allow GrDrawOpAtlas to grow as needed
Bug: skia:3550 Change-Id: Ib5312c8c06ba8549d90545658df6686c45058255 Reviewed-on: https://skia-review.googlesource.com/45841 Commit-Queue: Jim Van Verth <jvanverth@google.com> Reviewed-by: Robert Phillips <robertphillips@google.com>
-rw-r--r--src/gpu/GrDrawOpAtlas.cpp189
-rw-r--r--src/gpu/GrDrawOpAtlas.h15
-rw-r--r--src/gpu/GrGlyph.h1
-rw-r--r--src/gpu/GrProcessor.cpp4
-rw-r--r--src/gpu/GrProcessor.h1
-rw-r--r--src/gpu/effects/GrAtlasedShaderHelpers.h14
-rw-r--r--src/gpu/effects/GrBitmapTextGeoProc.cpp11
-rw-r--r--src/gpu/effects/GrBitmapTextGeoProc.h2
-rw-r--r--src/gpu/effects/GrDistanceFieldGeoProc.cpp33
-rw-r--r--src/gpu/effects/GrDistanceFieldGeoProc.h6
-rw-r--r--src/gpu/ops/GrAtlasTextOp.cpp35
-rw-r--r--src/gpu/ops/GrSmallPathRenderer.cpp41
-rw-r--r--src/gpu/text/GrAtlasGlyphCache.h9
-rw-r--r--src/gpu/text/GrAtlasTextBlob_regenInOp.cpp10
14 files changed, 267 insertions, 104 deletions
diff --git a/src/gpu/GrDrawOpAtlas.cpp b/src/gpu/GrDrawOpAtlas.cpp
index bdd07e7c82..22def06212 100644
--- a/src/gpu/GrDrawOpAtlas.cpp
+++ b/src/gpu/GrDrawOpAtlas.cpp
@@ -146,29 +146,8 @@ GrDrawOpAtlas::GrDrawOpAtlas(GrContext* context, GrPixelConfig config, int width
, fPixelConfig(config)
, fTextureWidth(width)
, fTextureHeight(height)
- , fAtlasGeneration(kInvalidAtlasGeneration + 1) {
-
- GrSurfaceDesc desc;
- desc.fFlags = kNone_GrSurfaceFlags;
- desc.fOrigin = kTopLeft_GrSurfaceOrigin;
- desc.fWidth = fTextureWidth;
- desc.fHeight = fTextureHeight;
- desc.fConfig = fPixelConfig;
-
- // We don't want to flush the context so we claim we're in the middle of flushing so as to
- // guarantee we do not recieve a texture with pending IO
- // TODO: Determine how to avoid having to do this. (https://bug.skia.org/4156)
- static const uint32_t kFlags = GrResourceProvider::kNoPendingIO_Flag;
- sk_sp<GrTexture> texture(context->resourceProvider()->createApproxTexture(desc, kFlags));
- if (texture) {
- // MDB TODO: for now, wrap an instantiated texture. Having the deferred instantiation
- // possess the correct properties (e.g., no pendingIO) should fall out of the system but
- // should receive special attention.
- // Note: When switching over to the deferred proxy, use the kExact flag to create
- // the atlas and assert that the width & height are powers of 2.
- fProxies[0] = GrSurfaceProxy::MakeWrapped(std::move(texture),
- kTopLeft_GrSurfaceOrigin);
- }
+ , fAtlasGeneration(kInvalidAtlasGeneration + 1)
+ , fNumPages(0) {
fPlotWidth = fTextureWidth / numPlotsX;
fPlotHeight = fTextureHeight / numPlotsY;
@@ -177,23 +156,8 @@ GrDrawOpAtlas::GrDrawOpAtlas(GrContext* context, GrPixelConfig config, int width
SkASSERT(fPlotHeight * numPlotsY == fTextureHeight);
SkDEBUGCODE(fNumPlots = numPlotsX * numPlotsY;)
- SkDEBUGCODE(fNumPages = 1;)
-
- // set up allocated plots
- fPages[0].fPlotArray.reset(new sk_sp<Plot>[ numPlotsX * numPlotsY ]);
- sk_sp<Plot>* currPlot = fPages[0].fPlotArray.get();
- for (int y = numPlotsY - 1, r = 0; y >= 0; --y, ++r) {
- for (int x = numPlotsX - 1, c = 0; x >= 0; --x, ++c) {
- uint32_t index = r * numPlotsX + c;
- currPlot->reset(
- new Plot(0, index, 1, x, y, fPlotWidth, fPlotHeight, fPixelConfig));
-
- // build LRU list
- fPages[0].fPlotList.addToHead(currPlot->get());
- ++currPlot;
- }
- }
+ this->createNewPage();
}
void GrDrawOpAtlas::processEviction(AtlasID id) {
@@ -234,57 +198,83 @@ inline bool GrDrawOpAtlas::updatePlot(GrDrawOp::Target* target, AtlasID* id, Plo
bool GrDrawOpAtlas::addToAtlas(AtlasID* id, GrDrawOp::Target* target, int width, int height,
const void* image, SkIPoint16* loc) {
- // Eventually we will iterate through these, for now just use the one.
- int pageIdx = 0;
-
- // We should already have a texture, TODO clean this up
- SkASSERT(fProxies[pageIdx]);
if (width > fPlotWidth || height > fPlotHeight) {
return false;
}
- // now look through all allocated plots for one we can share, in Most Recently Refed order
- PlotList::Iter plotIter;
- plotIter.init(fPages[pageIdx].fPlotList, PlotList::Iter::kHead_IterStart);
- Plot* plot;
- while ((plot = plotIter.get())) {
- SkASSERT(GrBytesPerPixel(fProxies[pageIdx]->config()) == plot->bpp());
- if (plot->addSubImage(width, height, image, loc)) {
- return this->updatePlot(target, id, plot);
+ // Look through each page to see if we can upload without having to flush
+ // We prioritize this upload to the first pages, not the most recently used, to make it easier
+ // to remove unused pages in reverse page order.
+ for (unsigned int pageIdx = 0; pageIdx < fNumPages; ++pageIdx) {
+ SkASSERT(fProxies[pageIdx]);
+ // look through all allocated plots for one we can share, in Most Recently Refed order
+ PlotList::Iter plotIter;
+ plotIter.init(fPages[pageIdx].fPlotList, PlotList::Iter::kHead_IterStart);
+ Plot* plot;
+ while ((plot = plotIter.get())) {
+ SkASSERT(GrBytesPerPixel(fProxies[pageIdx]->config()) == plot->bpp());
+ if (plot->addSubImage(width, height, image, loc)) {
+ return this->updatePlot(target, id, plot);
+ }
+ plotIter.next();
+ }
+
+ // If the above fails, then see if the least recently refed plot has already been
+ // flushed to the gpu
+ plot = fPages[pageIdx].fPlotList.tail();
+ SkASSERT(plot);
+ if (target->hasDrawBeenFlushed(plot->lastUseToken())) {
+ this->processEviction(plot->id());
+ plot->resetRects();
+ 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;
}
- plotIter.next();
}
- // If the above fails, then see if the least recently refed plot has already been flushed to the
- // gpu
- plot = fPages[pageIdx].fPlotList.tail();
- SkASSERT(plot);
- if (target->hasDrawBeenFlushed(plot->lastUseToken())) {
- this->processEviction(plot->id());
- plot->resetRects();
+ // If the simple cases fail, try to create a new page and add to it
+ if (this->createNewPage()) {
+ unsigned int pageIdx = fNumPages-1;
+ SkASSERT(fProxies[pageIdx]);
+ Plot* plot = fPages[pageIdx].fPlotList.head();
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;
+ if (plot->addSubImage(width, height, image, loc)) {
+ return this->updatePlot(target, id, plot);
}
- fAtlasGeneration++;
- return true;
+ // we shouldn't get here -- if so, something has gone terribly wrong
+ SkASSERT(false);
+ return false;
}
- // TODO: at this point try to create a new page and add to it before evicting
+ // Try to find a plot that we can perform an inline upload to.
+ // We prioritize this upload in reverse order of pages to counterbalance the order above.
+ Plot* plot = nullptr;
+ for (int pageIdx = (int)(fNumPages-1); pageIdx >= 0; --pageIdx) {
+ Plot* currentPlot = fPages[pageIdx].fPlotList.tail();
+ if (currentPlot->lastUseToken() != target->nextDrawToken()) {
+ plot = currentPlot;
+ break;
+ }
+ }
- // If this plot has been used in a draw that is currently being prepared by an op, then we have
- // to fail. This gives the op a chance to enqueue the draw, and call back into this function.
- // When that draw is enqueued, the draw token advances, and the subsequent call will continue
- // past this branch and prepare an inline upload that will occur after the enqueued draw which
- // references the plot's pre-upload content.
- if (plot->lastUseToken() == target->nextDrawToken()) {
+ // If we can't find a plot that is not used in a draw currently being prepared by an op, then
+ // we have to fail. This gives the op a chance to enqueue the draw, and call back into this
+ // function. When that draw is enqueued, the draw token advances, and the subsequent call will
+ // continue past this branch and prepare an inline upload that will occur after the enqueued
+ //draw which references the plot's pre-upload content.
+ if (!plot) {
return false;
}
this->processEviction(plot->id());
+ int pageIdx = GetPageIndexFromID(plot->id());
fPages[pageIdx].fPlotList.remove(plot);
sk_sp<Plot>& newPlot = fPages[pageIdx].fPlotArray[plot->index()];
newPlot.reset(plot->clone());
@@ -317,3 +307,56 @@ bool GrDrawOpAtlas::addToAtlas(AtlasID* id, GrDrawOp::Target* target, int width,
fAtlasGeneration++;
return true;
}
+
+bool GrDrawOpAtlas::createNewPage() {
+ if (fNumPages == kMaxPages) {
+ return false;
+ }
+
+ GrSurfaceDesc desc;
+ desc.fFlags = kNone_GrSurfaceFlags;
+ desc.fOrigin = kTopLeft_GrSurfaceOrigin;
+ desc.fWidth = fTextureWidth;
+ desc.fHeight = fTextureHeight;
+ desc.fConfig = fPixelConfig;
+
+ // We don't want to flush the context so we claim we're in the middle of flushing so as to
+ // guarantee we do not recieve a texture with pending IO
+ // TODO: Determine how to avoid having to do this. (https://bug.skia.org/4156)
+ static const uint32_t kFlags = GrResourceProvider::kNoPendingIO_Flag;
+ sk_sp<GrTexture> texture(fContext->resourceProvider()->createApproxTexture(desc, kFlags));
+ if (texture) {
+ // MDB TODO: for now, wrap an instantiated texture. Having the deferred instantiation
+ // possess the correct properties (e.g., no pendingIO) should fall out of the system but
+ // should receive special attention.
+ // Note: When switching over to the deferred proxy, use the kExact flag to create
+ // the atlas and assert that the width & height are powers of 2.
+ fProxies[fNumPages] = GrSurfaceProxy::MakeWrapped(std::move(texture),
+ kTopLeft_GrSurfaceOrigin);
+ }
+ if (!fProxies[fNumPages]) {
+ return false;
+ }
+
+ int numPlotsX = fTextureWidth/fPlotWidth;
+ int numPlotsY = fTextureHeight/fPlotHeight;
+
+ // set up allocated plots
+ fPages[fNumPages].fPlotArray.reset(new sk_sp<Plot>[ numPlotsX * numPlotsY ]);
+
+ sk_sp<Plot>* currPlot = fPages[fNumPages].fPlotArray.get();
+ for (int y = numPlotsY - 1, r = 0; y >= 0; --y, ++r) {
+ for (int x = numPlotsX - 1, c = 0; x >= 0; --x, ++c) {
+ uint32_t plotIndex = r * numPlotsX + c;
+ currPlot->reset(new Plot(fNumPages, plotIndex, 1, x, y, fPlotWidth, fPlotHeight,
+ fPixelConfig));
+
+ // build LRU list
+ fPages[fNumPages].fPlotList.addToHead(currPlot->get());
+ ++currPlot;
+ }
+ }
+
+ fNumPages++;
+ return true;
+}
diff --git a/src/gpu/GrDrawOpAtlas.h b/src/gpu/GrDrawOpAtlas.h
index 6d12973f4a..87d9c5b619 100644
--- a/src/gpu/GrDrawOpAtlas.h
+++ b/src/gpu/GrDrawOpAtlas.h
@@ -120,6 +120,7 @@ public:
}
static constexpr auto kMaxPages = 4;
+ uint32_t pageCount() { return fNumPages; }
/**
* A class which can be handed back to GrDrawOpAtlas for updating last use tokens in bulk. The
@@ -190,6 +191,10 @@ public:
return width > kGlyphMaxDim || height > kGlyphMaxDim;
}
+ static uint32_t GetPageIndexFromID(AtlasID id) {
+ return id & 0xff;
+ }
+
private:
GrDrawOpAtlas(GrContext*, GrPixelConfig config, int width, int height,
int numPlotsX, int numPlotsY);
@@ -252,7 +257,7 @@ private:
static GrDrawOpAtlas::AtlasID CreateId(uint32_t pageIdx, uint32_t plotIdx,
uint64_t generation) {
SkASSERT(pageIdx < (1 << 8));
- SkASSERT(pageIdx == 0); // for now, we only support one page
+ SkASSERT(pageIdx < kMaxPages);
SkASSERT(plotIdx < (1 << 8));
SkASSERT(generation < ((uint64_t)1 << 48));
return generation << 16 | plotIdx << 8 | pageIdx;
@@ -286,10 +291,6 @@ private:
typedef SkTInternalLList<Plot> PlotList;
- static uint32_t GetPageIndexFromID(AtlasID id) {
- return id & 0xff;
- }
-
static uint32_t GetPlotIndexFromID(AtlasID id) {
return (id >> 8) & 0xff;
}
@@ -312,6 +313,8 @@ private:
// TODO: make page MRU
}
+ bool createNewPage();
+
inline void processEviction(AtlasID);
GrContext* fContext;
@@ -340,7 +343,7 @@ private:
// proxies kept separate to make it easier to pass them up to client
sk_sp<GrTextureProxy> fProxies[kMaxPages];
Page fPages[kMaxPages];
- SkDEBUGCODE(uint32_t fNumPages;)
+ uint32_t fNumPages;
};
#endif
diff --git a/src/gpu/GrGlyph.h b/src/gpu/GrGlyph.h
index 5005b74543..fbd389e4ab 100644
--- a/src/gpu/GrGlyph.h
+++ b/src/gpu/GrGlyph.h
@@ -61,6 +61,7 @@ struct GrGlyph {
int height() const { return fBounds.height(); }
bool isEmpty() const { return fBounds.isEmpty(); }
uint16_t glyphID() const { return UnpackID(fPackedID); }
+ uint32_t pageIndex() const { return GrDrawOpAtlas::GetPageIndexFromID(fID); }
///////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/GrProcessor.cpp b/src/gpu/GrProcessor.cpp
index 7ea597221b..6650e208bc 100644
--- a/src/gpu/GrProcessor.cpp
+++ b/src/gpu/GrProcessor.cpp
@@ -137,6 +137,10 @@ void GrResourceIOProcessor::addImageStorageAccess(const ImageStorageAccess* acce
fImageStorageAccesses.push_back(access);
}
+void GrResourceIOProcessor::resetTextureSamplers() {
+ fTextureSamplers.reset();
+}
+
void GrResourceIOProcessor::addPendingIOs() const {
for (const auto& sampler : fTextureSamplers) {
sampler->programProxy()->markPendingIO();
diff --git a/src/gpu/GrProcessor.h b/src/gpu/GrProcessor.h
index de0598fed9..54aae35401 100644
--- a/src/gpu/GrProcessor.h
+++ b/src/gpu/GrProcessor.h
@@ -191,6 +191,7 @@ protected:
void addTextureSampler(const TextureSampler*);
void addBufferAccess(const BufferAccess*);
void addImageStorageAccess(const ImageStorageAccess*);
+ void resetTextureSamplers();
bool hasSameSamplersAndAccesses(const GrResourceIOProcessor&) const;
diff --git a/src/gpu/effects/GrAtlasedShaderHelpers.h b/src/gpu/effects/GrAtlasedShaderHelpers.h
index 67f2c242c2..50ac0efff4 100644
--- a/src/gpu/effects/GrAtlasedShaderHelpers.h
+++ b/src/gpu/effects/GrAtlasedShaderHelpers.h
@@ -47,17 +47,15 @@ static void append_multitexture_lookup(GrGLSLPrimitiveProcessor::EmitArgs& args,
const char* coordName,
const char* colorName) {
// conditionally load from the indexed texture sampler
- if (numTextureSamplers > 1) {
- args.fFragBuilder->codeAppendf("if (%s == 0) ", texIdx.fsIn());
+ for (int i = 0; i < numTextureSamplers-1; ++i) {
+ args.fFragBuilder->codeAppendf("if (%s == %d) { %s = ", texIdx.fsIn(), i, colorName);
+ args.fFragBuilder->appendTextureLookup(args.fTexSamplers[i], coordName, kVec2f_GrSLType);
+ args.fFragBuilder->codeAppend("; } else ");
}
args.fFragBuilder->codeAppendf("{ %s = ", colorName);
- args.fFragBuilder->appendTextureLookup(args.fTexSamplers[0], coordName, kVec2f_GrSLType);
+ args.fFragBuilder->appendTextureLookup(args.fTexSamplers[numTextureSamplers-1], coordName,
+ kVec2f_GrSLType);
args.fFragBuilder->codeAppend("; }");
- for (int i = 1; i < numTextureSamplers; ++i) {
- args.fFragBuilder->codeAppendf("else if (%s == %d) { %s =", texIdx.fsIn(), i, colorName);
- args.fFragBuilder->appendTextureLookup(args.fTexSamplers[i], coordName, kVec2f_GrSLType);
- args.fFragBuilder->codeAppend("; }");
- }
}
#endif
diff --git a/src/gpu/effects/GrBitmapTextGeoProc.cpp b/src/gpu/effects/GrBitmapTextGeoProc.cpp
index 2d665c50cb..4df5cdf4a4 100644
--- a/src/gpu/effects/GrBitmapTextGeoProc.cpp
+++ b/src/gpu/effects/GrBitmapTextGeoProc.cpp
@@ -149,6 +149,17 @@ GrBitmapTextGeoProc::GrBitmapTextGeoProc(GrColor color,
}
}
+void GrBitmapTextGeoProc::resetProxies(const sk_sp<GrTextureProxy> proxies[kMaxTextures],
+ const GrSamplerState& params) {
+ this->resetTextureSamplers();
+ for (int i = 0; i < kMaxTextures; ++i) {
+ if (proxies[i]) {
+ fTextureSamplers[i].reset(std::move(proxies[i]), params);
+ this->addTextureSampler(&fTextureSamplers[i]);
+ }
+ }
+}
+
void GrBitmapTextGeoProc::getGLSLProcessorKey(const GrShaderCaps& caps,
GrProcessorKeyBuilder* b) const {
GrGLBitmapTextGeoProc::GenKey(*this, caps, b);
diff --git a/src/gpu/effects/GrBitmapTextGeoProc.h b/src/gpu/effects/GrBitmapTextGeoProc.h
index f8f4d8e5a8..75ad021445 100644
--- a/src/gpu/effects/GrBitmapTextGeoProc.h
+++ b/src/gpu/effects/GrBitmapTextGeoProc.h
@@ -45,6 +45,8 @@ public:
const SkMatrix& localMatrix() const { return fLocalMatrix; }
bool usesLocalCoords() const { return fUsesLocalCoords; }
+ void resetProxies(const sk_sp<GrTextureProxy> proxies[kMaxTextures], const GrSamplerState& p);
+
void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps& caps) const override;
diff --git a/src/gpu/effects/GrDistanceFieldGeoProc.cpp b/src/gpu/effects/GrDistanceFieldGeoProc.cpp
index 66e96199eb..1758f34b2f 100644
--- a/src/gpu/effects/GrDistanceFieldGeoProc.cpp
+++ b/src/gpu/effects/GrDistanceFieldGeoProc.cpp
@@ -261,6 +261,17 @@ GrDistanceFieldA8TextGeoProc::GrDistanceFieldA8TextGeoProc(
}
}
+void GrDistanceFieldA8TextGeoProc::resetProxies(const sk_sp<GrTextureProxy> proxies[kMaxTextures],
+ const GrSamplerState& params) {
+ this->resetTextureSamplers();
+ for (int i = 0; i < kMaxTextures; ++i) {
+ if (proxies[i]) {
+ fTextureSamplers[i].reset(std::move(proxies[i]), params);
+ this->addTextureSampler(&fTextureSamplers[i]);
+ }
+ }
+}
+
void GrDistanceFieldA8TextGeoProc::getGLSLProcessorKey(const GrShaderCaps& caps,
GrProcessorKeyBuilder* b) const {
GrGLDistanceFieldA8TextGeoProc::GenKey(*this, caps, b);
@@ -511,6 +522,17 @@ GrDistanceFieldPathGeoProc::GrDistanceFieldPathGeoProc(
}
}
+void GrDistanceFieldPathGeoProc::resetProxies(const sk_sp<GrTextureProxy> proxies[kMaxTextures],
+ const GrSamplerState& params) {
+ this->resetTextureSamplers();
+ for (int i = 0; i < kMaxTextures; ++i) {
+ if (proxies[i]) {
+ fTextureSamplers[i].reset(std::move(proxies[i]), params);
+ this->addTextureSampler(&fTextureSamplers[i]);
+ }
+ }
+}
+
void GrDistanceFieldPathGeoProc::getGLSLProcessorKey(const GrShaderCaps& caps,
GrProcessorKeyBuilder* b) const {
GrGLDistanceFieldPathGeoProc::GenKey(*this, caps, b);
@@ -823,6 +845,17 @@ GrDistanceFieldLCDTextGeoProc::GrDistanceFieldLCDTextGeoProc(
}
}
+void GrDistanceFieldLCDTextGeoProc::resetProxies(const sk_sp<GrTextureProxy> proxies[kMaxTextures],
+ const GrSamplerState& params) {
+ this->resetTextureSamplers();
+ for (int i = 0; i < kMaxTextures; ++i) {
+ if (proxies[i]) {
+ fTextureSamplers[i].reset(std::move(proxies[i]), params);
+ this->addTextureSampler(&fTextureSamplers[i]);
+ }
+ }
+}
+
void GrDistanceFieldLCDTextGeoProc::getGLSLProcessorKey(const GrShaderCaps& caps,
GrProcessorKeyBuilder* b) const {
GrGLDistanceFieldLCDTextGeoProc::GenKey(*this, caps, b);
diff --git a/src/gpu/effects/GrDistanceFieldGeoProc.h b/src/gpu/effects/GrDistanceFieldGeoProc.h
index b5c6f9eea6..e7c02a5f59 100644
--- a/src/gpu/effects/GrDistanceFieldGeoProc.h
+++ b/src/gpu/effects/GrDistanceFieldGeoProc.h
@@ -87,6 +87,8 @@ public:
#endif
uint32_t getFlags() const { return fFlags; }
+ void resetProxies(const sk_sp<GrTextureProxy> proxies[kMaxTextures], const GrSamplerState& p);
+
void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
@@ -148,6 +150,8 @@ public:
uint32_t getFlags() const { return fFlags; }
bool usesLocalCoords() const { return fUsesLocalCoords; }
+ void resetProxies(const sk_sp<GrTextureProxy> proxies[kMaxTextures], const GrSamplerState& p);
+
void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
@@ -222,6 +226,8 @@ public:
uint32_t getFlags() const { return fFlags; }
bool usesLocalCoords() const { return fUsesLocalCoords; }
+ void resetProxies(const sk_sp<GrTextureProxy> proxies[kMaxTextures], const GrSamplerState& p);
+
void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
diff --git a/src/gpu/ops/GrAtlasTextOp.cpp b/src/gpu/ops/GrAtlasTextOp.cpp
index c6ceaac005..44100cba0d 100644
--- a/src/gpu/ops/GrAtlasTextOp.cpp
+++ b/src/gpu/ops/GrAtlasTextOp.cpp
@@ -84,25 +84,26 @@ void GrAtlasTextOp::onPrepareDraws(Target* target) {
return;
}
- const sk_sp<GrTextureProxy>* proxies = fFontCache->getProxies(this->maskFormat());
- if (!proxies[0]) {
+ GrMaskFormat maskFormat = this->maskFormat();
+
+ uint32_t atlasPageCount = fFontCache->getAtlasPageCount(maskFormat);
+ const sk_sp<GrTextureProxy>* proxies = fFontCache->getProxies(maskFormat);
+ if (!atlasPageCount || !proxies[0]) {
SkDebugf("Could not allocate backing texture for atlas\n");
return;
}
- GrMaskFormat maskFormat = this->maskFormat();
-
FlushInfo flushInfo;
flushInfo.fPipeline =
target->makePipeline(fSRGBFlags, std::move(fProcessors), target->detachAppliedClip());
if (this->usesDistanceFields()) {
flushInfo.fGeometryProcessor =
- this->setupDfProcessor(this->viewMatrix(),
- fLuminanceColor, this->color(), proxies);
+ this->setupDfProcessor(this->viewMatrix(),
+ fLuminanceColor, this->color(), proxies);
} else {
flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make(
- this->color(), proxies, GrSamplerState::ClampNearest(), maskFormat,
- localMatrix, this->usesLocalCoords());
+ this->color(), proxies, GrSamplerState::ClampNearest(), maskFormat,
+ localMatrix, this->usesLocalCoords());
}
flushInfo.fGlyphsToFlush = 0;
@@ -141,6 +142,24 @@ void GrAtlasTextOp::onPrepareDraws(Target* target) {
currVertex += byteCount;
}
+ // During preparation the number of atlas pages has increased.
+ // Update the proxies used in the GP to match.
+ if (atlasPageCount != fFontCache->getAtlasPageCount(maskFormat)) {
+ GrGeometryProcessor* gp = flushInfo.fGeometryProcessor.get();
+ if (this->usesDistanceFields()) {
+ if (this->isLCD()) {
+ reinterpret_cast<GrDistanceFieldLCDTextGeoProc*>(gp)->resetProxies(
+ fFontCache->getProxies(maskFormat), GrSamplerState::ClampBilerp());
+ } else {
+ reinterpret_cast<GrDistanceFieldA8TextGeoProc*>(gp)->resetProxies(
+ fFontCache->getProxies(maskFormat), GrSamplerState::ClampBilerp());
+ }
+ } else {
+ reinterpret_cast<GrBitmapTextGeoProc*>(gp)->resetProxies(
+ fFontCache->getProxies(maskFormat), GrSamplerState::ClampNearest());
+ }
+ }
+
this->flush(target, &flushInfo);
}
diff --git a/src/gpu/ops/GrSmallPathRenderer.cpp b/src/gpu/ops/GrSmallPathRenderer.cpp
index 6a037a6540..79d0061a82 100644
--- a/src/gpu/ops/GrSmallPathRenderer.cpp
+++ b/src/gpu/ops/GrSmallPathRenderer.cpp
@@ -238,6 +238,10 @@ private:
flushInfo.fPipeline = fHelper.makePipeline(target);
// Setup GrGeometryProcessor
GrDrawOpAtlas* atlas = fAtlas;
+ uint32_t atlasPageCount = atlas->pageCount();
+ if (!atlasPageCount) {
+ return;
+ }
if (fUsesDistanceField) {
uint32_t flags = 0;
flags |= ctm.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0;
@@ -385,6 +389,19 @@ private:
flushInfo.fInstancesToFlush++;
}
+ // During preparation the number of atlas pages has increased.
+ // Update the proxies used in the GP to match.
+ if (atlasPageCount != atlas->pageCount()) {
+ GrGeometryProcessor* gp = flushInfo.fGeometryProcessor.get();
+ if (fUsesDistanceField) {
+ reinterpret_cast<GrDistanceFieldPathGeoProc*>(gp)->resetProxies(
+ atlas->getProxies(), GrSamplerState::ClampBilerp());
+ } else {
+ reinterpret_cast<GrBitmapTextGeoProc*>(gp)->resetProxies(
+ atlas->getProxies(), GrSamplerState::ClampNearest());
+ }
+ }
+
this->flush(target, &flushInfo);
}
@@ -496,12 +513,17 @@ private:
shapeData->fBounds.fRight /= scale;
shapeData->fBounds.fBottom /= scale;
- shapeData->fTextureCoords.set((atlasLocation.fX+SK_DistanceFieldPad) << 1,
- (atlasLocation.fY+SK_DistanceFieldPad) << 1,
+ // We pack the 2bit page index in the low bit of the u and v texture coords
+ uint16_t pageIndex = GrDrawOpAtlas::GetPageIndexFromID(id);
+ SkASSERT(pageIndex < 4);
+ uint16_t uBit = (pageIndex >> 1) & 0x1;
+ uint16_t vBit = pageIndex & 0x1;
+ shapeData->fTextureCoords.set((atlasLocation.fX+SK_DistanceFieldPad) << 1 | uBit,
+ (atlasLocation.fY+SK_DistanceFieldPad) << 1 | vBit,
(atlasLocation.fX+SK_DistanceFieldPad+
- devPathBounds.width()) << 1,
+ devPathBounds.width()) << 1 | uBit,
(atlasLocation.fY+SK_DistanceFieldPad+
- devPathBounds.height()) << 1);
+ devPathBounds.height()) << 1 | vBit);
fShapeCache->add(shapeData);
fShapeList->addToTail(shapeData);
@@ -589,9 +611,14 @@ private:
shapeData->fBounds = SkRect::Make(devPathBounds);
shapeData->fBounds.offset(-translateX, -translateY);
- shapeData->fTextureCoords.set(atlasLocation.fX << 1, atlasLocation.fY << 1,
- (atlasLocation.fX+width) << 1,
- (atlasLocation.fY+height) << 1);
+ // We pack the 2bit page index in the low bit of the u and v texture coords
+ uint16_t pageIndex = GrDrawOpAtlas::GetPageIndexFromID(id);
+ SkASSERT(pageIndex < 4);
+ uint16_t uBit = (pageIndex >> 1) & 0x1;
+ uint16_t vBit = pageIndex & 0x1;
+ shapeData->fTextureCoords.set(atlasLocation.fX << 1 | uBit, atlasLocation.fY << 1 | vBit,
+ (atlasLocation.fX+width) << 1 | uBit,
+ (atlasLocation.fY+height) << 1 | vBit);
fShapeCache->add(shapeData);
fShapeList->addToTail(shapeData);
diff --git a/src/gpu/text/GrAtlasGlyphCache.h b/src/gpu/text/GrAtlasGlyphCache.h
index 81876a01d9..78b743e2f4 100644
--- a/src/gpu/text/GrAtlasGlyphCache.h
+++ b/src/gpu/text/GrAtlasGlyphCache.h
@@ -126,7 +126,7 @@ public:
void freeAll();
- // if getProxy returns nullptr, the client must not try to use other functions on the
+ // if getProxies returns nullptr, the client must not try to use other functions on the
// GrAtlasGlyphCache which use the atlas. This function *must* be called first, before other
// functions which use the atlas.
const sk_sp<GrTextureProxy>* getProxies(GrMaskFormat format) {
@@ -136,6 +136,13 @@ public:
return nullptr;
}
+ uint32_t getAtlasPageCount(GrMaskFormat format) {
+ if (this->initAtlas(format)) {
+ return this->getAtlas(format)->pageCount();
+ }
+ return 0;
+ }
+
bool hasGlyph(GrGlyph* glyph) {
SkASSERT(glyph);
return this->getAtlas(glyph->fMaskFormat)->hasID(glyph->fID);
diff --git a/src/gpu/text/GrAtlasTextBlob_regenInOp.cpp b/src/gpu/text/GrAtlasTextBlob_regenInOp.cpp
index b7911c3eae..778c9faabf 100644
--- a/src/gpu/text/GrAtlasTextBlob_regenInOp.cpp
+++ b/src/gpu/text/GrAtlasTextBlob_regenInOp.cpp
@@ -39,11 +39,19 @@ inline void regen_vertices(intptr_t vertex, const GrGlyph* glyph, size_t vertexS
u1 = u0 + width;
v1 = v0 + height;
}
- // shift to make space for index bits
+ // We pack the 2bit page index in the low bit of the u and v texture coords
+ uint32_t pageIndex = glyph->pageIndex();
+ SkASSERT(pageIndex < 4);
+ uint16_t uBit = (pageIndex >> 1) & 0x1;
+ uint16_t vBit = pageIndex & 0x1;
u0 <<= 1;
+ u0 |= uBit;
v0 <<= 1;
+ v0 |= vBit;
u1 <<= 1;
+ u1 |= uBit;
v1 <<= 1;
+ v1 |= vBit;
}
// This is a bit wonky, but sometimes we have LCD text, in which case we won't have color