From a950b63b442f1376d022740457b020ada62f6554 Mon Sep 17 00:00:00 2001 From: Jim Van Verth Date: Tue, 12 Sep 2017 11:54:11 -0400 Subject: Add support for additional textures in GrDrawOpAtlas Step two in supporting growable/shrinkable atlases. Bug: skia:3550 Change-Id: I0cdec2a9f59cc8ced071bfeec2f8ed5a228c4b7a Reviewed-on: https://skia-review.googlesource.com/43260 Commit-Queue: Jim Van Verth Reviewed-by: Robert Phillips --- src/gpu/GrDrawOpAtlas.cpp | 60 +++++++------ src/gpu/GrDrawOpAtlas.h | 133 ++++++++++++++++++----------- src/gpu/effects/GrBitmapTextGeoProc.cpp | 20 +++-- src/gpu/effects/GrBitmapTextGeoProc.h | 14 +-- src/gpu/effects/GrDistanceFieldGeoProc.cpp | 92 +++++++++++++------- src/gpu/effects/GrDistanceFieldGeoProc.h | 37 +++++--- src/gpu/ops/GrAtlasTextOp.cpp | 23 ++--- src/gpu/ops/GrAtlasTextOp.h | 5 +- src/gpu/ops/GrSmallPathRenderer.cpp | 4 +- src/gpu/text/GrAtlasGlyphCache.cpp | 14 +-- src/gpu/text/GrAtlasGlyphCache.h | 4 +- 11 files changed, 254 insertions(+), 152 deletions(-) (limited to 'src') diff --git a/src/gpu/GrDrawOpAtlas.cpp b/src/gpu/GrDrawOpAtlas.cpp index c962a6168d..bdd07e7c82 100644 --- a/src/gpu/GrDrawOpAtlas.cpp +++ b/src/gpu/GrDrawOpAtlas.cpp @@ -21,7 +21,7 @@ std::unique_ptr GrDrawOpAtlas::Make(GrContext* ctx, GrPixelConfig void* data) { std::unique_ptr atlas( new GrDrawOpAtlas(ctx, config, width, height, numPlotsX, numPlotsY)); - if (!atlas->getProxy()) { + if (!atlas->getProxies()[0]) { return nullptr; } @@ -32,13 +32,14 @@ std::unique_ptr GrDrawOpAtlas::Make(GrContext* ctx, GrPixelConfig //////////////////////////////////////////////////////////////////////////////// -GrDrawOpAtlas::Plot::Plot(int index, uint64_t genID, int offX, int offY, int width, int height, - GrPixelConfig config) +GrDrawOpAtlas::Plot::Plot(int pageIndex, int plotIndex, uint64_t genID, int offX, int offY, + int width, int height, GrPixelConfig config) : fLastUpload(GrDrawOpUploadToken::AlreadyFlushedToken()) , fLastUse(GrDrawOpUploadToken::AlreadyFlushedToken()) - , fIndex(index) + , fPageIndex(pageIndex) + , fPlotIndex(plotIndex) , fGenID(genID) - , fID(CreateId(fIndex, fGenID)) + , fID(CreateId(fPageIndex, fPlotIndex, fGenID)) , fData(nullptr) , fWidth(width) , fHeight(height) @@ -126,7 +127,7 @@ void GrDrawOpAtlas::Plot::resetRects() { } fGenID++; - fID = CreateId(fIndex, fGenID); + fID = CreateId(fPageIndex, fPlotIndex, fGenID); // zero out the plot if (fData) { @@ -142,7 +143,6 @@ void GrDrawOpAtlas::Plot::resetRects() { GrDrawOpAtlas::GrDrawOpAtlas(GrContext* context, GrPixelConfig config, int width, int height, int numPlotsX, int numPlotsY) : fContext(context) - , fProxy(nullptr) , fPixelConfig(config) , fTextureWidth(width) , fTextureHeight(height) @@ -166,7 +166,8 @@ GrDrawOpAtlas::GrDrawOpAtlas(GrContext* context, GrPixelConfig config, int width // 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. - fProxy = GrSurfaceProxy::MakeWrapped(std::move(texture), kTopLeft_GrSurfaceOrigin); + fProxies[0] = GrSurfaceProxy::MakeWrapped(std::move(texture), + kTopLeft_GrSurfaceOrigin); } fPlotWidth = fTextureWidth / numPlotsX; @@ -176,19 +177,20 @@ GrDrawOpAtlas::GrDrawOpAtlas(GrContext* context, GrPixelConfig config, int width SkASSERT(fPlotHeight * numPlotsY == fTextureHeight); SkDEBUGCODE(fNumPlots = numPlotsX * numPlotsY;) + SkDEBUGCODE(fNumPages = 1;) // set up allocated plots - fPlotArray.reset(new sk_sp[ numPlotsX * numPlotsY ]); + fPages[0].fPlotArray.reset(new sk_sp[ numPlotsX * numPlotsY ]); - sk_sp* currPlot = fPlotArray.get(); + sk_sp* 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(index, 1, x, y, fPlotWidth, fPlotHeight, fPixelConfig)); + new Plot(0, index, 1, x, y, fPlotWidth, fPlotHeight, fPixelConfig)); // build LRU list - fPlotList.addToHead(currPlot->get()); + fPages[0].fPlotList.addToHead(currPlot->get()); ++currPlot; } } @@ -201,7 +203,8 @@ void GrDrawOpAtlas::processEviction(AtlasID id) { } inline bool GrDrawOpAtlas::updatePlot(GrDrawOp::Target* target, AtlasID* id, Plot* plot) { - this->makeMRU(plot); + int pageIdx = GetPageIndexFromID(plot->id()); + this->makeMRU(plot, pageIdx); // If our most recent upload has already occurred then we have to insert a new // upload. Otherwise, we already have a scheduled upload that hasn't yet ocurred. @@ -212,11 +215,11 @@ inline bool GrDrawOpAtlas::updatePlot(GrDrawOp::Target* target, AtlasID* id, Plo // MDB TODO: this is currently fine since the atlas' proxy is always pre-instantiated. // Once it is deferred more care must be taken upon instantiation failure. - if (!fProxy->instantiate(fContext->resourceProvider())) { + if (!fProxies[pageIdx]->instantiate(fContext->resourceProvider())) { return false; } - GrTextureProxy* proxy = fProxy.get(); + GrTextureProxy* proxy = fProxies[pageIdx].get(); GrDrawOpUploadToken lastUploadToken = target->addAsapUpload( [plotsp, proxy] (GrDrawOp::WritePixelsFn& writePixels) { @@ -231,18 +234,21 @@ 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(fProxy); + 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(fPlotList, PlotList::Iter::kHead_IterStart); + plotIter.init(fPages[pageIdx].fPlotList, PlotList::Iter::kHead_IterStart); Plot* plot; while ((plot = plotIter.get())) { - SkASSERT(GrBytesPerPixel(fProxy->config()) == plot->bpp()); + SkASSERT(GrBytesPerPixel(fProxies[pageIdx]->config()) == plot->bpp()); if (plot->addSubImage(width, height, image, loc)) { return this->updatePlot(target, id, plot); } @@ -251,12 +257,12 @@ bool GrDrawOpAtlas::addToAtlas(AtlasID* id, GrDrawOp::Target* target, int width, // If the above fails, then see if the least recently refed plot has already been flushed to the // gpu - plot = fPlotList.tail(); + plot = fPages[pageIdx].fPlotList.tail(); SkASSERT(plot); if (target->hasDrawBeenFlushed(plot->lastUseToken())) { this->processEviction(plot->id()); plot->resetRects(); - SkASSERT(GrBytesPerPixel(fProxy->config()) == plot->bpp()); + SkASSERT(GrBytesPerPixel(fProxies[pageIdx]->config()) == plot->bpp()); SkDEBUGCODE(bool verify = )plot->addSubImage(width, height, image, loc); SkASSERT(verify); if (!this->updatePlot(target, id, plot)) { @@ -267,6 +273,8 @@ bool GrDrawOpAtlas::addToAtlas(AtlasID* id, GrDrawOp::Target* target, int width, return true; } + // TODO: at this point try to create a new page and add to it before evicting + // 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 @@ -277,12 +285,12 @@ bool GrDrawOpAtlas::addToAtlas(AtlasID* id, GrDrawOp::Target* target, int width, } this->processEviction(plot->id()); - fPlotList.remove(plot); - sk_sp& newPlot = fPlotArray[plot->index()]; + fPages[pageIdx].fPlotList.remove(plot); + sk_sp& newPlot = fPages[pageIdx].fPlotArray[plot->index()]; newPlot.reset(plot->clone()); - fPlotList.addToHead(newPlot.get()); - SkASSERT(GrBytesPerPixel(fProxy->config()) == newPlot->bpp()); + fPages[pageIdx].fPlotList.addToHead(newPlot.get()); + SkASSERT(GrBytesPerPixel(fProxies[pageIdx]->config()) == newPlot->bpp()); SkDEBUGCODE(bool verify = )newPlot->addSubImage(width, height, image, loc); SkASSERT(verify); @@ -292,10 +300,10 @@ bool GrDrawOpAtlas::addToAtlas(AtlasID* id, GrDrawOp::Target* target, int width, sk_sp plotsp(SkRef(newPlot.get())); // MDB TODO: this is currently fine since the atlas' proxy is always pre-instantiated. // Once it is deferred more care must be taken upon instantiation failure. - if (!fProxy->instantiate(fContext->resourceProvider())) { + if (!fProxies[pageIdx]->instantiate(fContext->resourceProvider())) { return false; } - GrTextureProxy* proxy = fProxy.get(); + GrTextureProxy* proxy = fProxies[pageIdx].get(); GrDrawOpUploadToken lastUploadToken = target->addInlineUpload( [plotsp, proxy] (GrDrawOp::WritePixelsFn& writePixels) { diff --git a/src/gpu/GrDrawOpAtlas.h b/src/gpu/GrDrawOpAtlas.h index 03eb8080a4..6d12973f4a 100644 --- a/src/gpu/GrDrawOpAtlas.h +++ b/src/gpu/GrDrawOpAtlas.h @@ -89,23 +89,28 @@ public: SkIPoint16* loc); GrContext* context() const { return fContext; } - sk_sp getProxy() const { return fProxy; } + const sk_sp* getProxies() const { return fProxies; } uint64_t atlasGeneration() const { return fAtlasGeneration; } inline bool hasID(AtlasID id) { - uint32_t index = GetIndexFromID(id); - SkASSERT(index < fNumPlots); - return fPlotArray[index]->genID() == GetGenerationFromID(id); + uint32_t plot = GetPlotIndexFromID(id); + SkASSERT(plot < fNumPlots); + uint32_t page = GetPageIndexFromID(id); + SkASSERT(page < fNumPages); + return fPages[page].fPlotArray[plot]->genID() == GetGenerationFromID(id); } /** To ensure the atlas does not evict a given entry, the client must set the last use token. */ inline void setLastUseToken(AtlasID id, GrDrawOpUploadToken token) { SkASSERT(this->hasID(id)); - uint32_t index = GetIndexFromID(id); - SkASSERT(index < fNumPlots); - this->makeMRU(fPlotArray[index].get()); - fPlotArray[index]->setLastUseToken(token); + uint32_t plotIdx = GetPlotIndexFromID(id); + SkASSERT(plotIdx < fNumPlots); + uint32_t pageIdx = GetPageIndexFromID(id); + SkASSERT(pageIdx < fNumPages); + Plot* plot = fPages[pageIdx].fPlotArray[plotIdx].get(); + this->makeMRU(plot, pageIdx); + plot->setLastUseToken(token); } inline void registerEvictionCallback(EvictionFunc func, void* userData) { @@ -114,47 +119,58 @@ public: data->fData = userData; } + static constexpr auto kMaxPages = 4; + /** * A class which can be handed back to GrDrawOpAtlas for updating last use tokens in bulk. The - * current max number of plots the GrDrawOpAtlas can handle is 32. If in the future this is - * insufficient then we can move to a 64 bit int. + * current max number of plots per page the GrDrawOpAtlas can handle is 32. If in the future + * this is insufficient then we can move to a 64 bit int. */ class BulkUseTokenUpdater { public: - BulkUseTokenUpdater() : fPlotAlreadyUpdated(0) {} + BulkUseTokenUpdater() { + memset(fPlotAlreadyUpdated, 0, sizeof(fPlotAlreadyUpdated)); + } BulkUseTokenUpdater(const BulkUseTokenUpdater& that) - : fPlotsToUpdate(that.fPlotsToUpdate) - , fPlotAlreadyUpdated(that.fPlotAlreadyUpdated) { + : fPlotsToUpdate(that.fPlotsToUpdate) { + memcpy(fPlotAlreadyUpdated, that.fPlotAlreadyUpdated, sizeof(fPlotAlreadyUpdated)); } void add(AtlasID id) { - int index = GrDrawOpAtlas::GetIndexFromID(id); - if (!this->find(index)) { - this->set(index); + int index = GrDrawOpAtlas::GetPlotIndexFromID(id); + int pageIdx = GrDrawOpAtlas::GetPageIndexFromID(id); + if (!this->find(pageIdx, index)) { + this->set(pageIdx, index); } } void reset() { fPlotsToUpdate.reset(); - fPlotAlreadyUpdated = 0; + memset(fPlotAlreadyUpdated, 0, sizeof(fPlotAlreadyUpdated)); } + struct PlotData { + PlotData(int pageIdx, int plotIdx) : fPageIndex(pageIdx), fPlotIndex(plotIdx) {} + uint32_t fPageIndex; + uint32_t fPlotIndex; + }; + private: - bool find(int index) const { + bool find(int pageIdx, int index) const { SkASSERT(index < kMaxPlots); - return (fPlotAlreadyUpdated >> index) & 1; + return (fPlotAlreadyUpdated[pageIdx] >> index) & 1; } - void set(int index) { - SkASSERT(!this->find(index)); - fPlotAlreadyUpdated = fPlotAlreadyUpdated | (1 << index); - fPlotsToUpdate.push_back(index); + void set(int pageIdx, int index) { + SkASSERT(!this->find(pageIdx, index)); + fPlotAlreadyUpdated[pageIdx] |= (1 << index); + fPlotsToUpdate.push_back(PlotData(pageIdx, index)); } - static const int kMinItems = 4; - static const int kMaxPlots = 32; - SkSTArray fPlotsToUpdate; - uint32_t fPlotAlreadyUpdated; + static constexpr int kMinItems = 4; + static constexpr int kMaxPlots = 32; + SkSTArray fPlotsToUpdate; + uint32_t fPlotAlreadyUpdated[kMaxPages]; friend class GrDrawOpAtlas; }; @@ -162,13 +178,14 @@ public: void setLastUseTokenBulk(const BulkUseTokenUpdater& updater, GrDrawOpUploadToken token) { int count = updater.fPlotsToUpdate.count(); for (int i = 0; i < count; i++) { - Plot* plot = fPlotArray[updater.fPlotsToUpdate[i]].get(); - this->makeMRU(plot); + const BulkUseTokenUpdater::PlotData& pd = updater.fPlotsToUpdate[i]; + Plot* plot = fPages[pd.fPageIndex].fPlotArray[pd.fPlotIndex].get(); + this->makeMRU(plot, pd.fPageIndex); plot->setLastUseToken(token); } } - static const int kGlyphMaxDim = 256; + static constexpr auto kGlyphMaxDim = 256; static bool GlyphTooLargeForAtlas(int width, int height) { return width > kGlyphMaxDim || height > kGlyphMaxDim; } @@ -188,8 +205,8 @@ private: SK_DECLARE_INTERNAL_LLIST_INTERFACE(Plot); public: - /** index() is a unique id for the plot relative to the owning GrAtlas. */ - uint32_t index() const { return fIndex; } + /** index() is a unique id for the plot relative to the owning GrAtlas and page. */ + uint32_t index() const { return fPlotIndex; } /** * genID() is incremented when the plot is evicted due to a atlas spill. It is used to know * if a particular subimage is still present in the atlas. @@ -219,7 +236,7 @@ private: void resetRects(); private: - Plot(int index, uint64_t genID, int offX, int offY, int width, int height, + Plot(int pageIndex, int plotIndex, uint64_t genID, int offX, int offY, int width, int height, GrPixelConfig config); ~Plot() override; @@ -229,19 +246,25 @@ private: * the atlas */ Plot* clone() const { - return new Plot(fIndex, fGenID + 1, fX, fY, fWidth, fHeight, fConfig); + return new Plot(fPageIndex, fPlotIndex, fGenID + 1, fX, fY, fWidth, fHeight, fConfig); } - static GrDrawOpAtlas::AtlasID CreateId(uint32_t index, uint64_t generation) { - SkASSERT(index < (1 << 16)); + 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(plotIdx < (1 << 8)); SkASSERT(generation < ((uint64_t)1 << 48)); - return generation << 16 | index; + return generation << 16 | plotIdx << 8 | pageIdx; } GrDrawOpUploadToken fLastUpload; GrDrawOpUploadToken fLastUse; - const uint32_t fIndex; + struct { + const uint32_t fPageIndex : 16; + const uint32_t fPlotIndex : 16; + }; uint64_t fGenID; GrDrawOpAtlas::AtlasID fID; unsigned char* fData; @@ -263,8 +286,12 @@ private: typedef SkTInternalLList PlotList; - static uint32_t GetIndexFromID(AtlasID id) { - return id & 0xffff; + static uint32_t GetPageIndexFromID(AtlasID id) { + return id & 0xff; + } + + static uint32_t GetPlotIndexFromID(AtlasID id) { + return (id >> 8) & 0xff; } // top 48 bits are reserved for the generation ID @@ -274,19 +301,20 @@ private: inline bool updatePlot(GrDrawOp::Target*, AtlasID*, Plot*); - inline void makeMRU(Plot* plot) { - if (fPlotList.head() == plot) { + inline void makeMRU(Plot* plot, int pageIdx) { + if (fPages[pageIdx].fPlotList.head() == plot) { return; } - fPlotList.remove(plot); - fPlotList.addToHead(plot); + fPages[pageIdx].fPlotList.remove(plot); + fPages[pageIdx].fPlotList.addToHead(plot); + + // TODO: make page MRU } inline void processEviction(AtlasID); GrContext* fContext; - sk_sp fProxy; GrPixelConfig fPixelConfig; int fTextureWidth; int fTextureHeight; @@ -302,10 +330,17 @@ private: }; SkTDArray fEvictionCallbacks; - // allocated array of Plots - std::unique_ptr[]> fPlotArray; - // LRU list of Plots (MRU at head - LRU at tail) - PlotList fPlotList; + + struct Page { + // allocated array of Plots + std::unique_ptr[]> fPlotArray; + // LRU list of Plots (MRU at head - LRU at tail) + PlotList fPlotList; + }; + // proxies kept separate to make it easier to pass them up to client + sk_sp fProxies[kMaxPages]; + Page fPages[kMaxPages]; + SkDEBUGCODE(uint32_t fNumPages;) }; #endif diff --git a/src/gpu/effects/GrBitmapTextGeoProc.cpp b/src/gpu/effects/GrBitmapTextGeoProc.cpp index 8013d2e4b8..2d665c50cb 100644 --- a/src/gpu/effects/GrBitmapTextGeoProc.cpp +++ b/src/gpu/effects/GrBitmapTextGeoProc.cpp @@ -120,13 +120,13 @@ private: /////////////////////////////////////////////////////////////////////////////// -GrBitmapTextGeoProc::GrBitmapTextGeoProc(GrColor color, sk_sp proxy, +GrBitmapTextGeoProc::GrBitmapTextGeoProc(GrColor color, + const sk_sp proxies[kMaxTextures], const GrSamplerState& params, GrMaskFormat format, const SkMatrix& localMatrix, bool usesLocalCoords) : fColor(color) , fLocalMatrix(localMatrix) , fUsesLocalCoords(usesLocalCoords) - , fTextureSampler(std::move(proxy), params) , fInColor(nullptr) , fMaskFormat(format) { this->initClassID(); @@ -141,7 +141,12 @@ GrBitmapTextGeoProc::GrBitmapTextGeoProc(GrColor color, sk_sp pr fInTextureCoords = &this->addVertexAttrib("inTextureCoords", kVec2us_uint_GrVertexAttribType, kHigh_GrSLPrecision); - this->addTextureSampler(&fTextureSampler); + 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, @@ -162,7 +167,12 @@ GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrBitmapTextGeoProc); sk_sp GrBitmapTextGeoProc::TestCreate(GrProcessorTestData* d) { int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : GrProcessorUnitTest::kAlphaTextureIdx; - sk_sp proxy = d->textureProxy(texIdx); + sk_sp proxies[kMaxTextures] = { + d->textureProxy(texIdx), + nullptr, + nullptr, + nullptr + }; GrSamplerState::WrapMode wrapModes[2]; GrTest::TestWrapModes(d->fRandom, wrapModes); @@ -183,7 +193,7 @@ sk_sp GrBitmapTextGeoProc::TestCreate(GrProcessorTestData* break; } - return GrBitmapTextGeoProc::Make(GrRandomColor(d->fRandom), std::move(proxy), samplerState, + return GrBitmapTextGeoProc::Make(GrRandomColor(d->fRandom), proxies, samplerState, format, GrTest::TestMatrix(d->fRandom), d->fRandom->nextBool()); } diff --git a/src/gpu/effects/GrBitmapTextGeoProc.h b/src/gpu/effects/GrBitmapTextGeoProc.h index c919d1c87b..f8f4d8e5a8 100644 --- a/src/gpu/effects/GrBitmapTextGeoProc.h +++ b/src/gpu/effects/GrBitmapTextGeoProc.h @@ -21,11 +21,14 @@ class GrInvariantOutput; */ class GrBitmapTextGeoProc : public GrGeometryProcessor { public: - static sk_sp Make(GrColor color, sk_sp proxy, + static constexpr int kMaxTextures = 4; + + static sk_sp Make(GrColor color, + const sk_sp proxies[kMaxTextures], const GrSamplerState& p, GrMaskFormat format, const SkMatrix& localMatrix, bool usesLocalCoords) { return sk_sp( - new GrBitmapTextGeoProc(color, std::move(proxy), p, format, + new GrBitmapTextGeoProc(color, proxies, p, format, localMatrix, usesLocalCoords)); } @@ -47,13 +50,14 @@ public: GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps& caps) const override; private: - GrBitmapTextGeoProc(GrColor, sk_sp, const GrSamplerState& params, - GrMaskFormat format, const SkMatrix& localMatrix, bool usesLocalCoords); + GrBitmapTextGeoProc(GrColor, const sk_sp proxies[kMaxTextures], + const GrSamplerState& params, GrMaskFormat format, + const SkMatrix& localMatrix, bool usesLocalCoords); GrColor fColor; SkMatrix fLocalMatrix; bool fUsesLocalCoords; - TextureSampler fTextureSampler; + TextureSampler fTextureSamplers[kMaxTextures]; const Attribute* fInPosition; const Attribute* fInColor; const Attribute* fInTextureCoords; diff --git a/src/gpu/effects/GrDistanceFieldGeoProc.cpp b/src/gpu/effects/GrDistanceFieldGeoProc.cpp index 953d4cc2bc..66e96199eb 100644 --- a/src/gpu/effects/GrDistanceFieldGeoProc.cpp +++ b/src/gpu/effects/GrDistanceFieldGeoProc.cpp @@ -228,18 +228,18 @@ private: /////////////////////////////////////////////////////////////////////////////// -GrDistanceFieldA8TextGeoProc::GrDistanceFieldA8TextGeoProc(GrColor color, - const SkMatrix& viewMatrix, - sk_sp proxy, - const GrSamplerState& params, +GrDistanceFieldA8TextGeoProc::GrDistanceFieldA8TextGeoProc( + GrColor color, + const SkMatrix& viewMatrix, + const sk_sp proxies[kMaxTextures], + const GrSamplerState& params, #ifdef SK_GAMMA_APPLY_TO_A8 - float distanceAdjust, + float distanceAdjust, #endif - uint32_t flags, - bool usesLocalCoords) + uint32_t flags, + bool usesLocalCoords) : fColor(color) , fViewMatrix(viewMatrix) - , fTextureSampler(std::move(proxy), params) #ifdef SK_GAMMA_APPLY_TO_A8 , fDistanceAdjust(distanceAdjust) #endif @@ -253,7 +253,12 @@ GrDistanceFieldA8TextGeoProc::GrDistanceFieldA8TextGeoProc(GrColor color, fInColor = &this->addVertexAttrib("inColor", kVec4ub_GrVertexAttribType); fInTextureCoords = &this->addVertexAttrib("inTextureCoords", kVec2us_uint_GrVertexAttribType, kHigh_GrSLPrecision); - this->addTextureSampler(&fTextureSampler); + 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, @@ -274,7 +279,12 @@ GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldA8TextGeoProc); sk_sp GrDistanceFieldA8TextGeoProc::TestCreate(GrProcessorTestData* d) { int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : GrProcessorUnitTest::kAlphaTextureIdx; - sk_sp proxy = d->textureProxy(texIdx); + sk_sp proxies[kMaxTextures] = { + d->textureProxy(texIdx), + nullptr, + nullptr, + nullptr + }; GrSamplerState::WrapMode wrapModes[2]; GrTest::TestWrapModes(d->fRandom, wrapModes); @@ -289,7 +299,7 @@ sk_sp GrDistanceFieldA8TextGeoProc::TestCreate(GrProcessorT } return GrDistanceFieldA8TextGeoProc::Make(GrRandomColor(d->fRandom), - GrTest::TestMatrix(d->fRandom), std::move(proxy), + GrTest::TestMatrix(d->fRandom), proxies, samplerState, #ifdef SK_GAMMA_APPLY_TO_A8 d->fRandom->nextF(), @@ -474,15 +484,15 @@ private: }; /////////////////////////////////////////////////////////////////////////////// -GrDistanceFieldPathGeoProc::GrDistanceFieldPathGeoProc(GrColor color, - const SkMatrix& viewMatrix, - sk_sp proxy, - const GrSamplerState& params, - uint32_t flags, - bool usesLocalCoords) +GrDistanceFieldPathGeoProc::GrDistanceFieldPathGeoProc( + GrColor color, + const SkMatrix& viewMatrix, + const sk_sp proxies[kMaxTextures], + const GrSamplerState& params, + uint32_t flags, + bool usesLocalCoords) : fColor(color) , fViewMatrix(viewMatrix) - , fTextureSampler(std::move(proxy), params) , fFlags(flags & kNonLCD_DistanceFieldEffectMask) , fInColor(nullptr) , fUsesLocalCoords(usesLocalCoords) { @@ -493,7 +503,12 @@ GrDistanceFieldPathGeoProc::GrDistanceFieldPathGeoProc(GrColor color, fInColor = &this->addVertexAttrib("inColor", kVec4ub_GrVertexAttribType); fInTextureCoords = &this->addVertexAttrib("inTextureCoords", kVec2us_uint_GrVertexAttribType, kHigh_GrSLPrecision); - this->addTextureSampler(&fTextureSampler); + 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, @@ -514,7 +529,12 @@ GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldPathGeoProc); sk_sp GrDistanceFieldPathGeoProc::TestCreate(GrProcessorTestData* d) { int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : GrProcessorUnitTest::kAlphaTextureIdx; - sk_sp proxy = d->textureProxy(texIdx); + sk_sp proxies[kMaxTextures] = { + d->textureProxy(texIdx), + nullptr, + nullptr, + nullptr + }; GrSamplerState::WrapMode wrapModes[2]; GrTest::TestWrapModes(d->fRandom, wrapModes); @@ -530,7 +550,7 @@ sk_sp GrDistanceFieldPathGeoProc::TestCreate(GrProcessorTes return GrDistanceFieldPathGeoProc::Make(GrRandomColor(d->fRandom), GrTest::TestMatrix(d->fRandom), - std::move(proxy), + proxies, samplerState, flags, d->fRandom->nextBool()); @@ -776,15 +796,15 @@ private: }; /////////////////////////////////////////////////////////////////////////////// -GrDistanceFieldLCDTextGeoProc::GrDistanceFieldLCDTextGeoProc(GrColor color, - const SkMatrix& viewMatrix, - sk_sp proxy, - const GrSamplerState& params, - DistanceAdjust distanceAdjust, - uint32_t flags, bool usesLocalCoords) +GrDistanceFieldLCDTextGeoProc::GrDistanceFieldLCDTextGeoProc( + GrColor color, + const SkMatrix& viewMatrix, + const sk_sp proxies[kMaxTextures], + const GrSamplerState& params, + DistanceAdjust distanceAdjust, + uint32_t flags, bool usesLocalCoords) : fColor(color) , fViewMatrix(viewMatrix) - , fTextureSampler(std::move(proxy), params) , fDistanceAdjust(distanceAdjust) , fFlags(flags & kLCD_DistanceFieldEffectMask) , fUsesLocalCoords(usesLocalCoords) { @@ -795,7 +815,12 @@ GrDistanceFieldLCDTextGeoProc::GrDistanceFieldLCDTextGeoProc(GrColor color, fInColor = &this->addVertexAttrib("inColor", kVec4ub_GrVertexAttribType); fInTextureCoords = &this->addVertexAttrib("inTextureCoords", kVec2us_uint_GrVertexAttribType, kHigh_GrSLPrecision); - this->addTextureSampler(&fTextureSampler); + 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, @@ -815,7 +840,12 @@ GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldLCDTextGeoProc); sk_sp GrDistanceFieldLCDTextGeoProc::TestCreate(GrProcessorTestData* d) { int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : GrProcessorUnitTest::kAlphaTextureIdx; - sk_sp proxy = d->textureProxy(texIdx); + sk_sp proxies[kMaxTextures] = { + d->textureProxy(texIdx), + nullptr, + nullptr, + nullptr + }; GrSamplerState::WrapMode wrapModes[2]; GrTest::TestWrapModes(d->fRandom, wrapModes); @@ -830,7 +860,7 @@ sk_sp GrDistanceFieldLCDTextGeoProc::TestCreate(GrProcessor } flags |= d->fRandom->nextBool() ? kBGR_DistanceFieldEffectFlag : 0; return GrDistanceFieldLCDTextGeoProc::Make(GrRandomColor(d->fRandom), - GrTest::TestMatrix(d->fRandom), std::move(proxy), + GrTest::TestMatrix(d->fRandom), proxies, samplerState, wa, flags, d->fRandom->nextBool()); } #endif diff --git a/src/gpu/effects/GrDistanceFieldGeoProc.h b/src/gpu/effects/GrDistanceFieldGeoProc.h index b1836dd9bb..b5c6f9eea6 100644 --- a/src/gpu/effects/GrDistanceFieldGeoProc.h +++ b/src/gpu/effects/GrDistanceFieldGeoProc.h @@ -50,22 +50,24 @@ enum GrDistanceFieldEffectFlags { */ class GrDistanceFieldA8TextGeoProc : public GrGeometryProcessor { public: + static constexpr int kMaxTextures = 4; + #ifdef SK_GAMMA_APPLY_TO_A8 static sk_sp Make(GrColor color, const SkMatrix& viewMatrix, - sk_sp proxy, + const sk_sp proxies[kMaxTextures], const GrSamplerState& params, float lum, uint32_t flags, bool usesLocalCoords) { return sk_sp( - new GrDistanceFieldA8TextGeoProc(color, viewMatrix, std::move(proxy), + new GrDistanceFieldA8TextGeoProc(color, viewMatrix, proxies, params, lum, flags, usesLocalCoords)); } #else static sk_sp Make(GrColor color, const SkMatrix& viewMatrix, - sk_sp proxy, + const sk_sp proxies[kMaxTextures], const GrSamplerState& params, uint32_t flags, bool usesLocalCoords) { return sk_sp( - new GrDistanceFieldA8TextGeoProc(color, viewMatrix, std::move(proxy), + new GrDistanceFieldA8TextGeoProc(color, viewMatrix, proxies, params, flags, usesLocalCoords)); } #endif @@ -90,7 +92,8 @@ public: GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override; private: - GrDistanceFieldA8TextGeoProc(GrColor, const SkMatrix& viewMatrix, sk_sp proxy, + GrDistanceFieldA8TextGeoProc(GrColor, const SkMatrix& viewMatrix, + const sk_sp proxies[kMaxTextures], const GrSamplerState& params, #ifdef SK_GAMMA_APPLY_TO_A8 float distanceAdjust, @@ -99,7 +102,7 @@ private: GrColor fColor; SkMatrix fViewMatrix; - TextureSampler fTextureSampler; + TextureSampler fTextureSamplers[kMaxTextures]; #ifdef SK_GAMMA_APPLY_TO_A8 float fDistanceAdjust; #endif @@ -122,12 +125,14 @@ private: */ class GrDistanceFieldPathGeoProc : public GrGeometryProcessor { public: + static constexpr int kMaxTextures = 4; + static sk_sp Make(GrColor color, const SkMatrix& viewMatrix, - sk_sp proxy, + const sk_sp proxies[kMaxTextures], const GrSamplerState& params, uint32_t flags, bool usesLocalCoords) { return sk_sp( - new GrDistanceFieldPathGeoProc(color, viewMatrix, std::move(proxy), + new GrDistanceFieldPathGeoProc(color, viewMatrix, proxies, params, flags, usesLocalCoords)); } @@ -148,12 +153,13 @@ public: GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override; private: - GrDistanceFieldPathGeoProc(GrColor, const SkMatrix& viewMatrix, sk_sp, + GrDistanceFieldPathGeoProc(GrColor, const SkMatrix& viewMatrix, + const sk_sp proxies[kMaxTextures], const GrSamplerState&, uint32_t flags, bool usesLocalCoords); GrColor fColor; SkMatrix fViewMatrix; - TextureSampler fTextureSampler; + TextureSampler fTextureSamplers[kMaxTextures]; uint32_t fFlags; const Attribute* fInPosition; const Attribute* fInColor; @@ -188,15 +194,17 @@ public: } }; + static constexpr int kMaxTextures = 4; + static sk_sp Make(GrColor color, const SkMatrix& viewMatrix, - sk_sp proxy, + const sk_sp proxies[kMaxTextures], const GrSamplerState& params, DistanceAdjust distanceAdjust, uint32_t flags, bool usesLocalCoords) { return sk_sp( - new GrDistanceFieldLCDTextGeoProc(color, viewMatrix, std::move(proxy), + new GrDistanceFieldLCDTextGeoProc(color, viewMatrix, proxies, params, distanceAdjust, flags, usesLocalCoords)); } @@ -219,13 +227,14 @@ public: GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override; private: - GrDistanceFieldLCDTextGeoProc(GrColor, const SkMatrix& viewMatrix, sk_sp proxy, + GrDistanceFieldLCDTextGeoProc(GrColor, const SkMatrix& viewMatrix, + const sk_sp proxies[kMaxTextures], const GrSamplerState& params, DistanceAdjust wa, uint32_t flags, bool usesLocalCoords); GrColor fColor; SkMatrix fViewMatrix; - TextureSampler fTextureSampler; + TextureSampler fTextureSamplers[kMaxTextures]; DistanceAdjust fDistanceAdjust; uint32_t fFlags; const Attribute* fInPosition; diff --git a/src/gpu/ops/GrAtlasTextOp.cpp b/src/gpu/ops/GrAtlasTextOp.cpp index bfdbfdbeeb..c6ceaac005 100644 --- a/src/gpu/ops/GrAtlasTextOp.cpp +++ b/src/gpu/ops/GrAtlasTextOp.cpp @@ -84,8 +84,8 @@ void GrAtlasTextOp::onPrepareDraws(Target* target) { return; } - sk_sp proxy = fFontCache->getProxy(this->maskFormat()); - if (!proxy) { + const sk_sp* proxies = fFontCache->getProxies(this->maskFormat()); + if (!proxies[0]) { SkDebugf("Could not allocate backing texture for atlas\n"); return; } @@ -98,10 +98,10 @@ void GrAtlasTextOp::onPrepareDraws(Target* target) { if (this->usesDistanceFields()) { flushInfo.fGeometryProcessor = this->setupDfProcessor(this->viewMatrix(), - fLuminanceColor, this->color(), std::move(proxy)); + fLuminanceColor, this->color(), proxies); } else { flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make( - this->color(), std::move(proxy), GrSamplerState::ClampNearest(), maskFormat, + this->color(), proxies, GrSamplerState::ClampNearest(), maskFormat, localMatrix, this->usesLocalCoords()); } @@ -218,10 +218,11 @@ bool GrAtlasTextOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) { // TODO just use class params // TODO trying to figure out why lcd is so whack -sk_sp GrAtlasTextOp::setupDfProcessor(const SkMatrix& viewMatrix, - SkColor luminanceColor, - GrColor color, - sk_sp proxy) const { +sk_sp GrAtlasTextOp::setupDfProcessor( + const SkMatrix& viewMatrix, + SkColor luminanceColor, + GrColor color, + const sk_sp p[kMaxTextures]) const { bool isLCD = this->isLCD(); // set up any flags uint32_t flags = viewMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0; @@ -247,7 +248,7 @@ sk_sp GrAtlasTextOp::setupDfProcessor(const SkMatrix& viewM GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make( redCorrection, greenCorrection, blueCorrection); - return GrDistanceFieldLCDTextGeoProc::Make(color, viewMatrix, std::move(proxy), + return GrDistanceFieldLCDTextGeoProc::Make(color, viewMatrix, p, GrSamplerState::ClampBilerp(), widthAdjust, flags, this->usesLocalCoords()); } else { @@ -258,11 +259,11 @@ sk_sp GrAtlasTextOp::setupDfProcessor(const SkMatrix& viewM correction = fDistanceAdjustTable->getAdjustment(lum >> kDistanceAdjustLumShift, fUseGammaCorrectDistanceTable); } - return GrDistanceFieldA8TextGeoProc::Make(color, viewMatrix, std::move(proxy), + return GrDistanceFieldA8TextGeoProc::Make(color, viewMatrix, p, GrSamplerState::ClampBilerp(), correction, flags, this->usesLocalCoords()); #else - return GrDistanceFieldA8TextGeoProc::Make(color, viewMatrix, std::move(proxy), + return GrDistanceFieldA8TextGeoProc::Make(color, viewMatrix, p, GrSamplerState::ClampBilerp(), flags, this->usesLocalCoords()); #endif diff --git a/src/gpu/ops/GrAtlasTextOp.h b/src/gpu/ops/GrAtlasTextOp.h index 5c37d45ea2..58e0515127 100644 --- a/src/gpu/ops/GrAtlasTextOp.h +++ b/src/gpu/ops/GrAtlasTextOp.h @@ -159,9 +159,12 @@ private: bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override; + static constexpr auto kMaxTextures = 4; + // TODO just use class params sk_sp setupDfProcessor(const SkMatrix& viewMatrix, SkColor luminanceColor, - GrColor color, sk_sp proxy) const; + GrColor color, + const sk_sp [kMaxTextures]) const; // The minimum number of Geometry we will try to allocate. diff --git a/src/gpu/ops/GrSmallPathRenderer.cpp b/src/gpu/ops/GrSmallPathRenderer.cpp index ec63e9ec7d..1c3cbe90fb 100644 --- a/src/gpu/ops/GrSmallPathRenderer.cpp +++ b/src/gpu/ops/GrSmallPathRenderer.cpp @@ -234,7 +234,7 @@ private: flags |= fGammaCorrect ? kGammaCorrect_DistanceFieldEffectFlag : 0; flushInfo.fGeometryProcessor = GrDistanceFieldPathGeoProc::Make( - this->color(), this->viewMatrix(), atlas->getProxy(), + this->color(), this->viewMatrix(), atlas->getProxies(), GrSamplerState::ClampBilerp(), flags, fHelper.usesLocalCoords()); } else { SkMatrix invert; @@ -249,7 +249,7 @@ private: } flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make( - this->color(), atlas->getProxy(), GrSamplerState::ClampNearest(), + this->color(), atlas->getProxies(), GrSamplerState::ClampNearest(), kA8_GrMaskFormat, invert, fHelper.usesLocalCoords()); } diff --git a/src/gpu/text/GrAtlasGlyphCache.cpp b/src/gpu/text/GrAtlasGlyphCache.cpp index 7456a8e4dc..1cf704a10e 100644 --- a/src/gpu/text/GrAtlasGlyphCache.cpp +++ b/src/gpu/text/GrAtlasGlyphCache.cpp @@ -176,16 +176,18 @@ void GrAtlasGlyphCache::dump() const { static int gDumpCount = 0; for (int i = 0; i < kMaskFormatCount; ++i) { if (fAtlases[i]) { - sk_sp proxy = fAtlases[i]->getProxy(); - if (proxy) { - SkString filename; + const sk_sp* proxies = fAtlases[i]->getProxies(); + for (int pageIdx = 0; pageIdx < GrDrawOpAtlas::kMaxPages; ++pageIdx) { + if (proxies[pageIdx]) { + SkString filename; #ifdef SK_BUILD_FOR_ANDROID - filename.printf("/sdcard/fontcache_%d%d.png", gDumpCount, i); + filename.printf("/sdcard/fontcache_%d%d%d.png", gDumpCount, i, pageIdx); #else - filename.printf("fontcache_%d%d.png", gDumpCount, i); + filename.printf("fontcache_%d%d%d.png", gDumpCount, i, pageIdx); #endif - save_pixels(fContext, proxy.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 167830fb99..81876a01d9 100644 --- a/src/gpu/text/GrAtlasGlyphCache.h +++ b/src/gpu/text/GrAtlasGlyphCache.h @@ -129,9 +129,9 @@ public: // if getProxy 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. - sk_sp getProxy(GrMaskFormat format) { + const sk_sp* getProxies(GrMaskFormat format) { if (this->initAtlas(format)) { - return this->getAtlas(format)->getProxy(); + return this->getAtlas(format)->getProxies(); } return nullptr; } -- cgit v1.2.3