From 5a4690bf26932c0d6940e4af8516d920e09ae81a Mon Sep 17 00:00:00 2001 From: Chris Craik Date: Tue, 14 Jul 2015 12:13:03 -0700 Subject: Clean up unncessary defines LOG_TAG and TRACE_TAG are already defined in the makefile Change-Id: I9e53e3dacbe018441edd74cb7c8c90846defee74 --- libs/hwui/TextureCache.cpp | 3 --- 1 file changed, 3 deletions(-) (limited to 'libs/hwui/TextureCache.cpp') diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp index fe1b7fdbfbbf..5b57c9186a3f 100644 --- a/libs/hwui/TextureCache.cpp +++ b/libs/hwui/TextureCache.cpp @@ -14,9 +14,6 @@ * limitations under the License. */ -#define LOG_TAG "OpenGLRenderer" -#define ATRACE_TAG ATRACE_TAG_VIEW - #include #include -- cgit v1.2.3-59-g8ed1b From 272a685f17cc4828257e521a6f62b7b17870f75e Mon Sep 17 00:00:00 2001 From: John Reck Date: Wed, 29 Jul 2015 16:48:58 -0700 Subject: Replace most usages of utils/Vector.h Change-Id: I540d1b3523244d6c71fc52d6fb30555271c25644 --- libs/hwui/AmbientShadow.cpp | 1 - libs/hwui/Caches.h | 5 ++- libs/hwui/DeferredDisplayList.cpp | 30 +++++++-------- libs/hwui/DeferredDisplayList.h | 9 +++-- libs/hwui/DisplayList.cpp | 10 +++-- libs/hwui/DisplayList.h | 23 ++++++------ libs/hwui/DisplayListCanvas.cpp | 11 +++--- libs/hwui/DisplayListCanvas.h | 4 +- libs/hwui/DisplayListOp.h | 8 ++-- libs/hwui/FontRenderer.cpp | 26 ++++++------- libs/hwui/FontRenderer.h | 14 +++---- libs/hwui/GradientCache.h | 2 - libs/hwui/OpenGLRenderer.cpp | 10 ++--- libs/hwui/OpenGLRenderer.h | 5 ++- libs/hwui/Patch.cpp | 3 +- libs/hwui/Patch.h | 6 +-- libs/hwui/PathCache.cpp | 7 +--- libs/hwui/PathCache.h | 5 ++- libs/hwui/PathTessellator.cpp | 67 +++++++++++++++------------------- libs/hwui/PathTessellator.h | 12 +++--- libs/hwui/Properties.h | 3 -- libs/hwui/RenderNode.cpp | 16 ++++---- libs/hwui/RenderNode.h | 13 ++++--- libs/hwui/ShadowTessellator.cpp | 1 - libs/hwui/TessellationCache.cpp | 6 +-- libs/hwui/TessellationCache.h | 1 - libs/hwui/TextureCache.cpp | 4 +- libs/hwui/TextureCache.h | 5 ++- libs/hwui/Vertex.h | 1 - libs/hwui/renderthread/CanvasContext.h | 1 - libs/hwui/renderthread/RenderProxy.h | 1 - libs/hwui/thread/TaskManager.cpp | 14 +++---- libs/hwui/thread/TaskManager.h | 7 ++-- 33 files changed, 159 insertions(+), 172 deletions(-) (limited to 'libs/hwui/TextureCache.cpp') diff --git a/libs/hwui/AmbientShadow.cpp b/libs/hwui/AmbientShadow.cpp index f8debcb28834..751531e1b57d 100644 --- a/libs/hwui/AmbientShadow.cpp +++ b/libs/hwui/AmbientShadow.cpp @@ -54,7 +54,6 @@ #include #include -#include #include "AmbientShadow.h" #include "ShadowTessellator.h" diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h index c617a4d868a2..049d58bcd133 100644 --- a/libs/hwui/Caches.h +++ b/libs/hwui/Caches.h @@ -43,12 +43,13 @@ #include #include -#include #include #include +#include + namespace android { namespace uirenderer { @@ -201,7 +202,7 @@ private: std::unique_ptr mRegionMesh; mutable Mutex mGarbageLock; - Vector mLayerGarbage; + std::vector mLayerGarbage; bool mInitialized; diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp index e56d2bec7ff2..9fb1e756c00d 100644 --- a/libs/hwui/DeferredDisplayList.cpp +++ b/libs/hwui/DeferredDisplayList.cpp @@ -69,7 +69,7 @@ public: // NOTE: ignore empty bounds special case, since we don't merge across those ops mBounds.unionWith(state->mBounds); mAllOpsOpaque &= opaqueOverBounds; - mOps.add(OpStatePair(op, state)); + mOps.push_back(OpStatePair(op, state)); } bool intersects(const Rect& rect) { @@ -133,7 +133,7 @@ public: inline int count() const { return mOps.size(); } protected: - Vector mOps; + std::vector mOps; Rect mBounds; // union of bounds of contained ops private: bool mAllOpsOpaque; @@ -418,7 +418,7 @@ void DeferredDisplayList::addSaveLayer(OpenGLRenderer& renderer, this, op, op->getFlags(), newSaveCount); storeStateOpBarrier(renderer, op); - mSaveStack.push(newSaveCount); + mSaveStack.push_back(newSaveCount); } /** @@ -433,7 +433,7 @@ void DeferredDisplayList::addSave(OpenGLRenderer& renderer, SaveOp* op, int newS // store and replay the save operation, as it may be needed to correctly playback the clip DEFER_LOGD(" adding save barrier with new save count %d", newSaveCount); storeStateOpBarrier(renderer, op); - mSaveStack.push(newSaveCount); + mSaveStack.push_back(newSaveCount); } } @@ -456,11 +456,11 @@ void DeferredDisplayList::addRestoreToCount(OpenGLRenderer& renderer, StateOp* o resetBatchingState(); } - if (mSaveStack.isEmpty() || newSaveCount > mSaveStack.top()) { + if (mSaveStack.empty() || newSaveCount > mSaveStack.back()) { return; } - while (!mSaveStack.isEmpty() && mSaveStack.top() >= newSaveCount) mSaveStack.pop(); + while (!mSaveStack.empty() && mSaveStack.back() >= newSaveCount) mSaveStack.pop_back(); storeRestoreToCountBarrier(renderer, op, mSaveStack.size() + FLUSH_SAVE_STACK_DEPTH); } @@ -492,7 +492,7 @@ void DeferredDisplayList::addDrawOp(OpenGLRenderer& renderer, DrawOp* op) { // the merge path in those cases deferInfo.mergeable &= !recordingComplexClip(); deferInfo.opaqueOverBounds &= !recordingComplexClip() - && mSaveStack.isEmpty() + && mSaveStack.empty() && !state->mRoundRectClipState; if (CC_LIKELY(mAvoidOverdraw) && mBatches.size() && @@ -507,7 +507,7 @@ void DeferredDisplayList::addDrawOp(OpenGLRenderer& renderer, DrawOp* op) { // TODO: elegant way to reuse batches? DrawBatch* b = new DrawBatch(deferInfo); b->add(op, state, deferInfo.opaqueOverBounds); - mBatches.add(b); + mBatches.push_back(b); return; } @@ -517,12 +517,12 @@ void DeferredDisplayList::addDrawOp(OpenGLRenderer& renderer, DrawOp* op) { // insertion point of a new batch, will hopefully be immediately after similar batch // (eventually, should be similar shader) int insertBatchIndex = mBatches.size(); - if (!mBatches.isEmpty()) { + if (!mBatches.empty()) { if (state->mBounds.isEmpty()) { // don't know the bounds for op, so add to last batch and start from scratch on next op DrawBatch* b = new DrawBatch(deferInfo); b->add(op, state, deferInfo.opaqueOverBounds); - mBatches.add(b); + mBatches.push_back(b); resetBatchingState(); #if DEBUG_DEFER DEFER_LOGD("Warning: Encountered op with empty bounds, resetting batches"); @@ -586,7 +586,7 @@ void DeferredDisplayList::addDrawOp(OpenGLRenderer& renderer, DrawOp* op) { DEFER_LOGD("creating %singBatch %p, bid %x, at %d", deferInfo.mergeable ? "Merg" : "Draw", targetBatch, deferInfo.batchId, insertBatchIndex); - mBatches.insertAt(targetBatch, insertBatchIndex); + mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch); } targetBatch->add(op, state, deferInfo.opaqueOverBounds); @@ -597,7 +597,7 @@ void DeferredDisplayList::storeStateOpBarrier(OpenGLRenderer& renderer, StateOp* DeferredDisplayState* state = createState(); renderer.storeDisplayState(*state, getStateOpDeferFlags()); - mBatches.add(new StateOpBatch(op, state)); + mBatches.push_back(new StateOpBatch(op, state)); resetBatchingState(); } @@ -610,7 +610,7 @@ void DeferredDisplayList::storeRestoreToCountBarrier(OpenGLRenderer& renderer, S // doesn't have kClip_SaveFlag set DeferredDisplayState* state = createState(); renderer.storeDisplayState(*state, getStateOpDeferFlags()); - mBatches.add(new RestoreToCountBatch(op, state, newSaveCount)); + mBatches.push_back(new RestoreToCountBatch(op, state, newSaveCount)); resetBatchingState(); } @@ -618,7 +618,7 @@ void DeferredDisplayList::storeRestoreToCountBarrier(OpenGLRenderer& renderer, S // Replay / flush ///////////////////////////////////////////////////////////////////////////////// -static void replayBatchList(const Vector& batchList, +static void replayBatchList(const std::vector& batchList, OpenGLRenderer& renderer, Rect& dirty) { for (unsigned int i = 0; i < batchList.size(); i++) { @@ -664,7 +664,7 @@ void DeferredDisplayList::discardDrawingBatches(const unsigned int maxIndex) { // leave deferred state ops alone for simplicity (empty save restore pairs may now exist) if (mBatches[i] && mBatches[i]->purelyDrawBatch()) { delete mBatches[i]; - mBatches.replaceAt(nullptr, i); + mBatches[i] = nullptr; } } mEarliestUnclearedIndex = maxIndex + 1; diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h index 160c1ad2d1f6..4f2dca5f3ee1 100644 --- a/libs/hwui/DeferredDisplayList.h +++ b/libs/hwui/DeferredDisplayList.h @@ -19,13 +19,14 @@ #include #include -#include #include #include "Matrix.h" #include "OpenGLRenderer.h" #include "Rect.h" +#include + class SkBitmap; namespace android { @@ -100,7 +101,7 @@ public: kOpBatch_Count, // Add other batch ids before this }; - bool isEmpty() { return mBatches.isEmpty(); } + bool isEmpty() { return mBatches.empty(); } /** * Plays back all of the draw ops recorded into batches to the renderer. @@ -157,10 +158,10 @@ private: * that when an associated restoreToCount is deferred, it can be recorded as a * RestoreToCountBatch */ - Vector mSaveStack; + std::vector mSaveStack; int mComplexClipStackStart; - Vector mBatches; + std::vector mBatches; // Maps batch ids to the most recent *non-merging* batch of that id Batch* mBatchLookup[kOpBatch_Count]; diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp index eacfac7d93a0..0af9420533eb 100644 --- a/libs/hwui/DisplayList.cpp +++ b/libs/hwui/DisplayList.cpp @@ -40,13 +40,13 @@ void DisplayListData::cleanupResources() { resourceCache.lock(); for (size_t i = 0; i < patchResources.size(); i++) { - resourceCache.decrementRefcountLocked(patchResources.itemAt(i)); + resourceCache.decrementRefcountLocked(patchResources[i]); } resourceCache.unlock(); for (size_t i = 0; i < pathResources.size(); i++) { - const SkPath* path = pathResources.itemAt(i); + const SkPath* path = pathResources[i]; if (path->unique() && Caches::hasInstance()) { Caches::getInstance().pathCache.removeDeferred(path); } @@ -60,8 +60,10 @@ void DisplayListData::cleanupResources() { } size_t DisplayListData::addChild(DrawRenderNodeOp* op) { - mReferenceHolders.push(op->renderNode()); - return mChildren.add(op); + mReferenceHolders.push_back(op->renderNode()); + size_t index = mChildren.size(); + mChildren.push_back(op); + return index; } }; // namespace uirenderer diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h index d7615484c975..0bdb8169ea06 100644 --- a/libs/hwui/DisplayList.h +++ b/libs/hwui/DisplayList.h @@ -27,7 +27,6 @@ #include #include #include -#include #include @@ -39,6 +38,8 @@ #include "Matrix.h" #include "RenderProperties.h" +#include + class SkBitmap; class SkPaint; class SkPath; @@ -124,28 +125,28 @@ public: ~DisplayListData(); // pointers to all ops within display list, pointing into allocator data - Vector displayListOps; + std::vector displayListOps; // index of DisplayListOp restore, after which projected descendents should be drawn int projectionReceiveIndex; - Vector bitmapResources; - Vector pathResources; - Vector patchResources; + std::vector bitmapResources; + std::vector pathResources; + std::vector patchResources; std::vector> paints; std::vector> regions; Vector functors; - const Vector& getChunks() const { + const std::vector& getChunks() const { return chunks; } size_t addChild(DrawRenderNodeOp* childOp); - const Vector& children() { return mChildren; } + const std::vector& children() { return mChildren; } void ref(VirtualLightRefBase* prop) { - mReferenceHolders.push(prop); + mReferenceHolders.push_back(prop); } size_t getUsedSize() { @@ -156,12 +157,12 @@ public: } private: - Vector< sp > mReferenceHolders; + std::vector< sp > mReferenceHolders; // list of children display lists for quick, non-drawing traversal - Vector mChildren; + std::vector mChildren; - Vector chunks; + std::vector chunks; // allocator into which all ops were allocated LinearAllocator allocator; diff --git a/libs/hwui/DisplayListCanvas.cpp b/libs/hwui/DisplayListCanvas.cpp index af18e03c60a9..74189aabbc87 100644 --- a/libs/hwui/DisplayListCanvas.cpp +++ b/libs/hwui/DisplayListCanvas.cpp @@ -548,11 +548,12 @@ void DisplayListCanvas::flushTranslate() { } size_t DisplayListCanvas::addOpAndUpdateChunk(DisplayListOp* op) { - int insertIndex = mDisplayListData->displayListOps.add(op); + int insertIndex = mDisplayListData->displayListOps.size(); + mDisplayListData->displayListOps.push_back(op); if (mDeferredBarrierType != kBarrier_None) { // op is first in new chunk - mDisplayListData->chunks.push(); - DisplayListData::Chunk& newChunk = mDisplayListData->chunks.editTop(); + mDisplayListData->chunks.emplace_back(); + DisplayListData::Chunk& newChunk = mDisplayListData->chunks.back(); newChunk.beginOpIndex = insertIndex; newChunk.endOpIndex = insertIndex + 1; newChunk.reorderChildren = (mDeferredBarrierType == kBarrier_OutOfOrder); @@ -562,7 +563,7 @@ size_t DisplayListCanvas::addOpAndUpdateChunk(DisplayListOp* op) { mDeferredBarrierType = kBarrier_None; } else { // standard case - append to existing chunk - mDisplayListData->chunks.editTop().endOpIndex = insertIndex + 1; + mDisplayListData->chunks.back().endOpIndex = insertIndex + 1; } return insertIndex; } @@ -594,7 +595,7 @@ size_t DisplayListCanvas::addRenderNodeOp(DrawRenderNodeOp* op) { int childIndex = mDisplayListData->addChild(op); // update the chunk's child indices - DisplayListData::Chunk& chunk = mDisplayListData->chunks.editTop(); + DisplayListData::Chunk& chunk = mDisplayListData->chunks.back(); chunk.endChildIndex = childIndex + 1; if (op->renderNode()->stagingProperties().isProjectionReceiver()) { diff --git a/libs/hwui/DisplayListCanvas.h b/libs/hwui/DisplayListCanvas.h index 6f2e2b50967e..28954d1bba70 100644 --- a/libs/hwui/DisplayListCanvas.h +++ b/libs/hwui/DisplayListCanvas.h @@ -270,7 +270,7 @@ private: // The points/verbs within the path are refcounted so this copy operation // is inexpensive and maintains the generationID of the original path. const SkPath* cachedPath = new SkPath(*path); - mDisplayListData->pathResources.add(cachedPath); + mDisplayListData->pathResources.push_back(cachedPath); return cachedPath; } @@ -345,7 +345,7 @@ private: } inline const Res_png_9patch* refPatch(const Res_png_9patch* patch) { - mDisplayListData->patchResources.add(patch); + mDisplayListData->patchResources.push_back(patch); mResourceCache.incrementRefcount(patch); return patch; } diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h index 8b4b4ba2b79e..8ff58d4f64f5 100644 --- a/libs/hwui/DisplayListOp.h +++ b/libs/hwui/DisplayListOp.h @@ -139,7 +139,7 @@ public: * reducing which operations are tagged as mergeable. */ virtual void multiDraw(OpenGLRenderer& renderer, Rect& dirty, - const Vector& ops, const Rect& bounds) { + const std::vector& ops, const Rect& bounds) { for (unsigned int i = 0; i < ops.size(); i++) { renderer.restoreDisplayState(*(ops[i].state), true); ops[i].op->applyDraw(renderer, dirty); @@ -648,7 +648,7 @@ public: * the current layer, if any. */ virtual void multiDraw(OpenGLRenderer& renderer, Rect& dirty, - const Vector& ops, const Rect& bounds) override { + const std::vector& ops, const Rect& bounds) override { const DeferredDisplayState& firstState = *(ops[0].state); renderer.restoreDisplayState(firstState, true); // restore all but the clip @@ -819,7 +819,7 @@ public: * is also responsible for dirtying the current layer, if any. */ virtual void multiDraw(OpenGLRenderer& renderer, Rect& dirty, - const Vector& ops, const Rect& bounds) override { + const std::vector& ops, const Rect& bounds) override { const DeferredDisplayState& firstState = *(ops[0].state); renderer.restoreDisplayState(firstState, true); // restore all but the clip @@ -1358,7 +1358,7 @@ public: } virtual void multiDraw(OpenGLRenderer& renderer, Rect& dirty, - const Vector& ops, const Rect& bounds) override { + const std::vector& ops, const Rect& bounds) override { for (unsigned int i = 0; i < ops.size(); i++) { const DeferredDisplayState& state = *(ops[i].state); DrawOpMode drawOpMode = (i == ops.size() - 1) ? DrawOpMode::kFlush : DrawOpMode::kDefer; diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index 9c2c1192a69d..9be8c7d45bca 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -134,7 +134,7 @@ FontRenderer::FontRenderer() sLogFontRendererCreate = false; } -void clearCacheTextures(Vector& cacheTextures) { +void clearCacheTextures(std::vector& cacheTextures) { for (uint32_t i = 0; i < cacheTextures.size(); i++) { delete cacheTextures[i]; } @@ -171,7 +171,7 @@ void FontRenderer::flushAllAndInvalidate() { mDrawn = false; } -void FontRenderer::flushLargeCaches(Vector& cacheTextures) { +void FontRenderer::flushLargeCaches(std::vector& cacheTextures) { // Start from 1; don't deallocate smallest/default texture for (uint32_t i = 1; i < cacheTextures.size(); i++) { CacheTexture* cacheTexture = cacheTextures[i]; @@ -191,7 +191,7 @@ void FontRenderer::flushLargeCaches() { flushLargeCaches(mRGBACacheTextures); } -CacheTexture* FontRenderer::cacheBitmapInTexture(Vector& cacheTextures, +CacheTexture* FontRenderer::cacheBitmapInTexture(std::vector& cacheTextures, const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) { for (uint32_t i = 0; i < cacheTextures.size(); i++) { if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) { @@ -218,7 +218,7 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp // choose an appropriate cache texture list for this glyph format SkMask::Format format = static_cast(glyph.fMaskFormat); - Vector* cacheTextures = nullptr; + std::vector* cacheTextures = nullptr; switch (format) { case SkMask::kA8_Format: case SkMask::kBW_Format: @@ -399,17 +399,17 @@ void FontRenderer::initTextTexture() { clearCacheTextures(mRGBACacheTextures); mUploadTexture = false; - mACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, + mACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, GL_ALPHA, true)); - mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, + mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, GL_ALPHA, false)); - mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, + mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, GL_ALPHA, false)); - mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight, + mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight, GL_ALPHA, false)); - mRGBACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, + mRGBACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, GL_RGBA, false)); - mRGBACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, + mRGBACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, GL_RGBA, false)); mCurrentCacheTexture = mACacheTextures[0]; } @@ -425,7 +425,7 @@ void FontRenderer::checkInit() { mInitialized = true; } -void checkTextureUpdateForCache(Caches& caches, Vector& cacheTextures, +void checkTextureUpdateForCache(Caches& caches, std::vector& cacheTextures, bool& resetPixelStore, GLuint& lastTextureId) { for (uint32_t i = 0; i < cacheTextures.size(); i++) { CacheTexture* cacheTexture = cacheTextures[i]; @@ -470,7 +470,7 @@ void FontRenderer::checkTextureUpdate() { mUploadTexture = false; } -void FontRenderer::issueDrawCommand(Vector& cacheTextures) { +void FontRenderer::issueDrawCommand(std::vector& cacheTextures) { if (!mFunctor) return; bool first = true; @@ -739,7 +739,7 @@ void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, flo Blur::vertical(gaussian.get(), intRadius, scratch.get(), *image, width, height); } -static uint32_t calculateCacheSize(const Vector& cacheTextures) { +static uint32_t calculateCacheSize(const std::vector& cacheTextures) { uint32_t size = 0; for (uint32_t i = 0; i < cacheTextures.size(); i++) { CacheTexture* cacheTexture = cacheTextures[i]; diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h index dfb107c99bc5..2954975b1413 100644 --- a/libs/hwui/FontRenderer.h +++ b/libs/hwui/FontRenderer.h @@ -21,16 +21,16 @@ #include "font/CacheTexture.h" #include "font/CachedGlyphInfo.h" #include "font/Font.h" -#include "utils/SortedList.h" #include -#include #include #include #include +#include + #ifdef ANDROID_ENABLE_RENDERSCRIPT #include "RenderScript.h" namespace RSC { @@ -75,7 +75,7 @@ public: FontRenderer(); ~FontRenderer(); - void flushLargeCaches(Vector& cacheTextures); + void flushLargeCaches(std::vector& cacheTextures); void flushLargeCaches(); void setGammaTable(const uint8_t* gammaTable) { @@ -127,7 +127,7 @@ private: CacheTexture* createCacheTexture(int width, int height, GLenum format, bool allocate); void cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph, uint32_t *retOriginX, uint32_t *retOriginY, bool precaching); - CacheTexture* cacheBitmapInTexture(Vector& cacheTextures, const SkGlyph& glyph, + CacheTexture* cacheBitmapInTexture(std::vector& cacheTextures, const SkGlyph& glyph, uint32_t* startX, uint32_t* startY); void flushAllAndInvalidate(); @@ -136,7 +136,7 @@ private: void initRender(const Rect* clip, Rect* bounds, TextDrawFunctor* functor); void finishRender(); - void issueDrawCommand(Vector& cacheTextures); + void issueDrawCommand(std::vector& cacheTextures); void issueDrawCommand(); void appendMeshQuadNoClip(float x1, float y1, float u1, float v1, float x2, float y2, float u2, float v2, @@ -164,8 +164,8 @@ private: uint32_t mLargeCacheWidth; uint32_t mLargeCacheHeight; - Vector mACacheTextures; - Vector mRGBACacheTextures; + std::vector mACacheTextures; + std::vector mRGBACacheTextures; Font* mCurrentFont; LruCache mActiveFonts; diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h index 08319ea1ec9b..7534c5d11164 100644 --- a/libs/hwui/GradientCache.h +++ b/libs/hwui/GradientCache.h @@ -25,7 +25,6 @@ #include #include -#include namespace android { namespace uirenderer { @@ -183,7 +182,6 @@ private: bool mUseFloatTexture; bool mHasNpot; - Vector mGarbage; mutable Mutex mLock; }; // class GradientCache diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index c260f5fe79d3..8e04bdf3b8ad 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -419,7 +419,7 @@ void OpenGLRenderer::updateLayers() { // Note: it is very important to update the layers in order for (int i = 0; i < count; i++) { - Layer* layer = mLayerUpdates.itemAt(i).get(); + Layer* layer = mLayerUpdates[i].get(); updateLayer(layer, false); } @@ -438,7 +438,7 @@ void OpenGLRenderer::flushLayers() { // Note: it is very important to update the layers in order for (int i = 0; i < count; i++) { - mLayerUpdates.itemAt(i)->flush(); + mLayerUpdates[i]->flush(); } mLayerUpdates.clear(); @@ -455,7 +455,7 @@ void OpenGLRenderer::pushLayerUpdate(Layer* layer) { // the insertion order. The linear search is not an issue since // this list is usually very short (typically one item, at most a few) for (int i = mLayerUpdates.size() - 1; i >= 0; i--) { - if (mLayerUpdates.itemAt(i) == layer) { + if (mLayerUpdates[i] == layer) { return; } } @@ -466,8 +466,8 @@ void OpenGLRenderer::pushLayerUpdate(Layer* layer) { void OpenGLRenderer::cancelLayerUpdate(Layer* layer) { if (layer) { for (int i = mLayerUpdates.size() - 1; i >= 0; i--) { - if (mLayerUpdates.itemAt(i) == layer) { - mLayerUpdates.removeAt(i); + if (mLayerUpdates[i] == layer) { + mLayerUpdates.erase(mLayerUpdates.begin() + i); break; } } diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 402f6edd475d..390f6207f4ea 100755 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -44,12 +44,13 @@ #include #include #include -#include #include #include +#include + class SkShader; namespace android { @@ -855,7 +856,7 @@ private: // List of rectangles to clear after saveLayer() is invoked std::vector mLayers; // List of layers to update at the beginning of a frame - Vector< sp > mLayerUpdates; + std::vector< sp > mLayerUpdates; // See PROPERTY_DISABLE_SCISSOR_OPTIMIZATION in // Properties.h diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp index 15d2ae94aeaa..500f9e95381c 100644 --- a/libs/hwui/Patch.cpp +++ b/libs/hwui/Patch.cpp @@ -206,8 +206,7 @@ void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, f // Record all non empty quads if (hasEmptyQuads) { - Rect bounds(x1, y1, x2, y2); - quads.add(bounds); + quads.emplace_back(x1, y1, x2, y2); } mUvMapper.map(u1, v1, u2, v2); diff --git a/libs/hwui/Patch.h b/libs/hwui/Patch.h index b63bd24456d3..f04416ccabf9 100644 --- a/libs/hwui/Patch.h +++ b/libs/hwui/Patch.h @@ -21,13 +21,13 @@ #include -#include - #include #include "Rect.h" #include "UvMapper.h" +#include + namespace android { namespace uirenderer { @@ -52,7 +52,7 @@ public: uint32_t verticesCount = 0; uint32_t indexCount = 0; bool hasEmptyQuads = false; - Vector quads; + std::vector quads; GLintptr positionOffset = 0; GLintptr textureOffset = 0; diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp index e36f5f17d29c..f503e5d6e8ba 100644 --- a/libs/hwui/PathCache.cpp +++ b/libs/hwui/PathCache.cpp @@ -338,7 +338,7 @@ void PathCache::PathProcessor::onProcess(const sp >& task) { void PathCache::removeDeferred(const SkPath* path) { Mutex::Autolock l(mLock); - mGarbage.push(path->getGenerationID()); + mGarbage.push_back(path->getGenerationID()); } void PathCache::clearGarbage() { @@ -346,10 +346,7 @@ void PathCache::clearGarbage() { { // scope for the mutex Mutex::Autolock l(mLock); - size_t count = mGarbage.size(); - for (size_t i = 0; i < count; i++) { - const uint32_t generationID = mGarbage.itemAt(i); - + for (const uint32_t generationID : mGarbage) { LruCache::Iterator iter(mCache); while (iter.next()) { const PathDescription& key = iter.key(); diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h index 70148631db34..31f8d3553375 100644 --- a/libs/hwui/PathCache.h +++ b/libs/hwui/PathCache.h @@ -28,7 +28,8 @@ #include #include #include -#include + +#include class SkBitmap; class SkCanvas; @@ -307,7 +308,7 @@ private: sp mProcessor; - Vector mGarbage; + std::vector mGarbage; mutable Mutex mLock; }; // class PathCache diff --git a/libs/hwui/PathTessellator.cpp b/libs/hwui/PathTessellator.cpp index 5294be887c93..8fa187c1e530 100644 --- a/libs/hwui/PathTessellator.cpp +++ b/libs/hwui/PathTessellator.cpp @@ -177,7 +177,8 @@ public: } }; -void getFillVerticesFromPerimeter(const Vector& perimeter, VertexBuffer& vertexBuffer) { +void getFillVerticesFromPerimeter(const std::vector& perimeter, + VertexBuffer& vertexBuffer) { Vertex* buffer = vertexBuffer.alloc(perimeter.size()); int currentIndex = 0; @@ -201,8 +202,8 @@ void getFillVerticesFromPerimeter(const Vector& perimeter, VertexBuffer& * Uses an additional 2 vertices at the end to wrap around, closing the tri-strip * (for a total of perimeter.size() * 2 + 2 vertices) */ -void getStrokeVerticesFromPerimeter(const PaintInfo& paintInfo, const Vector& perimeter, - VertexBuffer& vertexBuffer) { +void getStrokeVerticesFromPerimeter(const PaintInfo& paintInfo, + const std::vector& perimeter, VertexBuffer& vertexBuffer) { Vertex* buffer = vertexBuffer.alloc(perimeter.size() * 2 + 2); int currentIndex = 0; @@ -260,7 +261,7 @@ static inline void storeBeginEnd(const PaintInfo& paintInfo, const Vertex& cente * 2 - can zig-zag across 'extra' vertices at either end, to create round caps */ void getStrokeVerticesFromUnclosedVertices(const PaintInfo& paintInfo, - const Vector& vertices, VertexBuffer& vertexBuffer) { + const std::vector& vertices, VertexBuffer& vertexBuffer) { const int extra = paintInfo.capExtraDivisions(); const int allocSize = (vertices.size() + extra) * 2; Vertex* buffer = vertexBuffer.alloc(allocSize); @@ -339,8 +340,9 @@ void getStrokeVerticesFromUnclosedVertices(const PaintInfo& paintInfo, * * 3 - zig zag back and forth inside the shape to fill it (using perimeter.size() vertices) */ -void getFillVerticesFromPerimeterAA(const PaintInfo& paintInfo, const Vector& perimeter, - VertexBuffer& vertexBuffer, float maxAlpha = 1.0f) { +void getFillVerticesFromPerimeterAA(const PaintInfo& paintInfo, + const std::vector& perimeter, VertexBuffer& vertexBuffer, + float maxAlpha = 1.0f) { AlphaVertex* buffer = vertexBuffer.alloc(perimeter.size() * 3 + 2); // generate alpha points - fill Alpha vertex gaps in between each point with @@ -398,7 +400,7 @@ void getFillVerticesFromPerimeterAA(const PaintInfo& paintInfo, const Vector& vertices, +inline static void storeCapAA(const PaintInfo& paintInfo, const std::vector& vertices, AlphaVertex* buffer, bool isFirst, Vector2 normal, int offset) { const int extra = paintInfo.capExtraDivisions(); const int extraOffset = (extra + 1) / 2; @@ -423,8 +425,8 @@ inline static void storeCapAA(const PaintInfo& paintInfo, const Vector& } // determine referencePoint, the center point for the 4 primary cap vertices - const Vertex* point = isFirst ? vertices.begin() : (vertices.end() - 1); - Vector2 referencePoint = {point->x, point->y}; + const Vertex& point = isFirst ? vertices.front() : vertices.back(); + Vector2 referencePoint = {point.x, point.y}; if (paintInfo.cap == SkPaint::kSquare_Cap) { // To account for square cap, move the primary cap vertices (that create the AA edge) by the // stroke offset vector (rotated to be parallel to the stroke) @@ -569,7 +571,7 @@ or, for rounded caps: = 2 + 6 * pts + 6 * roundDivs */ void getStrokeVerticesFromUnclosedVerticesAA(const PaintInfo& paintInfo, - const Vector& vertices, VertexBuffer& vertexBuffer) { + const std::vector& vertices, VertexBuffer& vertexBuffer) { const int extra = paintInfo.capExtraDivisions(); const int allocSize = 6 * vertices.size() + 2 + 6 * extra; @@ -642,8 +644,8 @@ void getStrokeVerticesFromUnclosedVerticesAA(const PaintInfo& paintInfo, } -void getStrokeVerticesFromPerimeterAA(const PaintInfo& paintInfo, const Vector& perimeter, - VertexBuffer& vertexBuffer) { +void getStrokeVerticesFromPerimeterAA(const PaintInfo& paintInfo, + const std::vector& perimeter, VertexBuffer& vertexBuffer) { AlphaVertex* buffer = vertexBuffer.alloc(6 * perimeter.size() + 8); int offset = 2 * perimeter.size() + 3; @@ -721,7 +723,7 @@ void PathTessellator::tessellatePath(const SkPath &path, const SkPaint* paint, const PaintInfo paintInfo(paint, transform); - Vector tempVertices; + std::vector tempVertices; float threshInvScaleX = paintInfo.inverseScaleX; float threshInvScaleY = paintInfo.inverseScaleY; if (paintInfo.style == SkPaint::kStroke_Style) { @@ -816,7 +818,7 @@ void PathTessellator::tessellatePoints(const float* points, int count, const SkP } // calculate outline - Vector outlineVertices; + std::vector outlineVertices; PathApproximationInfo approximationInfo(paintInfo.inverseScaleX, paintInfo.inverseScaleY, OUTLINE_REFINE_THRESHOLD); approximatePathOutlineVertices(path, true, approximationInfo, outlineVertices); @@ -858,10 +860,8 @@ void PathTessellator::tessellateLines(const float* points, int count, const SkPa vertexBuffer.alloc(numLines * lineAllocSize + (numLines - 1) * 2); } - Vector tempVertices; - tempVertices.push(); - tempVertices.push(); - Vertex* tempVerticesData = tempVertices.editArray(); + std::vector tempVertices(2); + Vertex* tempVerticesData = &tempVertices.front(); Rect bounds; bounds.set(points[0], points[1], points[0], points[1]); for (int i = 0; i < count; i += 4) { @@ -897,18 +897,11 @@ void PathTessellator::tessellateLines(const float* points, int count, const SkPa /////////////////////////////////////////////////////////////////////////////// bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, float threshold, - Vector& outputVertices) { + std::vector& outputVertices) { PathApproximationInfo approximationInfo(1.0f, 1.0f, threshold); return approximatePathOutlineVertices(path, true, approximationInfo, outputVertices); } -void pushToVector(Vector& vertices, float x, float y) { - // TODO: make this not yuck - vertices.push(); - Vertex* newVertex = &(vertices.editArray()[vertices.size() - 1]); - Vertex::set(newVertex, x, y); -} - class ClockwiseEnforcer { public: void addPoint(const SkPoint& point) { @@ -924,15 +917,15 @@ public: lastX = x; lastY = y; } - void reverseVectorIfNotClockwise(Vector& vertices) { + void reverseVectorIfNotClockwise(std::vector& vertices) { if (sum < 0) { // negative sum implies CounterClockwise const int size = vertices.size(); for (int i = 0; i < size / 2; i++) { Vertex tmp = vertices[i]; int k = size - 1 - i; - vertices.replaceAt(vertices[k], i); - vertices.replaceAt(tmp, k); + vertices[i] = vertices[k]; + vertices[k] = tmp; } } } @@ -944,7 +937,7 @@ private: }; bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool forceClose, - const PathApproximationInfo& approximationInfo, Vector& outputVertices) { + const PathApproximationInfo& approximationInfo, std::vector& outputVertices) { ATRACE_CALL(); // TODO: to support joins other than sharp miter, join vertices should be labelled in the @@ -956,7 +949,7 @@ bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool fo while (SkPath::kDone_Verb != (v = iter.next(pts))) { switch (v) { case SkPath::kMove_Verb: - pushToVector(outputVertices, pts[0].x(), pts[0].y()); + outputVertices.push_back(Vertex{pts[0].x(), pts[0].y()}); ALOGV("Move to pos %f %f", pts[0].x(), pts[0].y()); clockwiseEnforcer.addPoint(pts[0]); break; @@ -966,7 +959,7 @@ bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool fo break; case SkPath::kLine_Verb: ALOGV("kLine_Verb %f %f -> %f %f", pts[0].x(), pts[0].y(), pts[1].x(), pts[1].y()); - pushToVector(outputVertices, pts[1].x(), pts[1].y()); + outputVertices.push_back(Vertex{pts[1].x(), pts[1].y()}); clockwiseEnforcer.addPoint(pts[1]); break; case SkPath::kQuad_Verb: @@ -1017,7 +1010,7 @@ bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool fo int size = outputVertices.size(); if (size >= 2 && outputVertices[0].x == outputVertices[size - 1].x && outputVertices[0].y == outputVertices[size - 1].y) { - outputVertices.pop(); + outputVertices.pop_back(); wasClosed = true; } @@ -1045,7 +1038,7 @@ void PathTessellator::recursiveCubicBezierVertices( float p1x, float p1y, float c1x, float c1y, float p2x, float p2y, float c2x, float c2y, const PathApproximationInfo& approximationInfo, - Vector& outputVertices, int depth) { + std::vector& outputVertices, int depth) { float dx = p2x - p1x; float dy = p2y - p1y; float d1 = fabs((c1x - p2x) * dy - (c1y - p2y) * dx); @@ -1055,7 +1048,7 @@ void PathTessellator::recursiveCubicBezierVertices( if (depth >= MAX_DEPTH || d * d <= getThreshold(approximationInfo, dx, dy)) { // below thresh, draw line by adding endpoint - pushToVector(outputVertices, p2x, p2y); + outputVertices.push_back(Vertex{p2x, p2y}); } else { float p1c1x = (p1x + c1x) * 0.5f; float p1c1y = (p1y + c1y) * 0.5f; @@ -1090,7 +1083,7 @@ void PathTessellator::recursiveQuadraticBezierVertices( float bx, float by, float cx, float cy, const PathApproximationInfo& approximationInfo, - Vector& outputVertices, int depth) { + std::vector& outputVertices, int depth) { float dx = bx - ax; float dy = by - ay; // d is the cross product of vector (B-A) and (C-B). @@ -1099,7 +1092,7 @@ void PathTessellator::recursiveQuadraticBezierVertices( if (depth >= MAX_DEPTH || d * d <= getThreshold(approximationInfo, dx, dy)) { // below thresh, draw line by adding endpoint - pushToVector(outputVertices, bx, by); + outputVertices.push_back(Vertex{bx, by}); } else { float acx = (ax + cx) * 0.5f; float bcx = (bx + cx) * 0.5f; diff --git a/libs/hwui/PathTessellator.h b/libs/hwui/PathTessellator.h index 16c8b36a6a9d..b66e83252fb3 100644 --- a/libs/hwui/PathTessellator.h +++ b/libs/hwui/PathTessellator.h @@ -17,13 +17,13 @@ #ifndef ANDROID_HWUI_PATH_TESSELLATOR_H #define ANDROID_HWUI_PATH_TESSELLATOR_H -#include - #include "Matrix.h" #include "Rect.h" #include "Vertex.h" #include "VertexBuffer.h" +#include + namespace android { namespace uirenderer { @@ -109,11 +109,11 @@ public: * @param outputVertices An empty Vector which will be populated with the output */ static bool approximatePathOutlineVertices(const SkPath &path, float threshold, - Vector &outputVertices); + std::vector &outputVertices); private: static bool approximatePathOutlineVertices(const SkPath &path, bool forceClose, - const PathApproximationInfo& approximationInfo, Vector &outputVertices); + const PathApproximationInfo& approximationInfo, std::vector &outputVertices); /* endpoints a & b, @@ -124,7 +124,7 @@ private: float bx, float by, float cx, float cy, const PathApproximationInfo& approximationInfo, - Vector &outputVertices, int depth = 0); + std::vector &outputVertices, int depth = 0); /* endpoints p1, p2 @@ -136,7 +136,7 @@ private: float p2x, float p2y, float c2x, float c2y, const PathApproximationInfo& approximationInfo, - Vector &outputVertices, int depth = 0); + std::vector &outputVertices, int depth = 0); }; }; // namespace uirenderer diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 5aef2a568798..1a70d7c20f03 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -36,9 +36,6 @@ namespace uirenderer { // If turned on, text is interpreted as glyphs instead of UTF-16 #define RENDER_TEXT_AS_GLYPHS 1 -// Indicates whether to remove the biggest layers first, or the smaller ones -#define LAYER_REMOVE_BIGGEST_FIRST 0 - // Textures used by layers must have dimensions multiples of this number #define LAYER_SIZE 64 diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 3717aec43cbf..af8aaa20342e 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -528,7 +528,7 @@ void RenderNode::computeOrdering() { void RenderNode::computeOrderingImpl( DrawRenderNodeOp* opState, const SkPath* outlineOfProjectionSurface, - Vector* compositedChildrenOfProjectionSurface, + std::vector* compositedChildrenOfProjectionSurface, const mat4* transformFromProjectionSurface) { mProjectedNodes.clear(); if (mDisplayListData == nullptr || mDisplayListData->isEmpty()) return; @@ -542,7 +542,7 @@ void RenderNode::computeOrderingImpl( // composited projectee, flag for out of order draw, save matrix, and store in proj surface opState->mSkipInOrderDraw = true; opState->mTransformFromCompositingAncestor.load(localTransformFromProjectionSurface); - compositedChildrenOfProjectionSurface->add(opState); + compositedChildrenOfProjectionSurface->push_back(opState); } else { // standard in order draw opState->mSkipInOrderDraw = false; @@ -556,7 +556,7 @@ void RenderNode::computeOrderingImpl( RenderNode* child = childOp->mRenderNode; const SkPath* projectionOutline = nullptr; - Vector* projectionChildren = nullptr; + std::vector* projectionChildren = nullptr; const mat4* projectionTransform = nullptr; if (isProjectionReceiver && !child->properties().getProjectBackwards()) { // if receiving projections, collect projecting descendant @@ -638,7 +638,7 @@ void RenderNode::replay(ReplayStateStruct& replayStruct, const int level) { } void RenderNode::buildZSortedChildList(const DisplayListData::Chunk& chunk, - Vector& zTranslatedNodes) { + std::vector& zTranslatedNodes) { if (chunk.beginChildIndex == chunk.endChildIndex) return; for (unsigned int i = chunk.beginChildIndex; i < chunk.endChildIndex; i++) { @@ -647,7 +647,7 @@ void RenderNode::buildZSortedChildList(const DisplayListData::Chunk& chunk, float childZ = child->properties().getZ(); if (!MathUtils::isZero(childZ) && chunk.reorderChildren) { - zTranslatedNodes.add(ZDrawRenderNodeOpPair(childZ, childOp)); + zTranslatedNodes.push_back(ZDrawRenderNodeOpPair(childZ, childOp)); childOp->mSkipInOrderDraw = true; } else if (!child->properties().getProjectBackwards()) { // regular, in order drawing DisplayList @@ -719,7 +719,7 @@ void RenderNode::issueDrawShadowOperation(const Matrix4& transformFromParent, T& template void RenderNode::issueOperationsOf3dChildren(ChildrenSelectMode mode, - const Matrix4& initialTransform, const Vector& zTranslatedNodes, + const Matrix4& initialTransform, const std::vector& zTranslatedNodes, OpenGLRenderer& renderer, T& handler) { const int size = zTranslatedNodes.size(); if (size == 0 @@ -896,7 +896,7 @@ void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) { for (size_t chunkIndex = 0; chunkIndex < mDisplayListData->getChunks().size(); chunkIndex++) { const DisplayListData::Chunk& chunk = mDisplayListData->getChunks()[chunkIndex]; - Vector zTranslatedNodes; + std::vector zTranslatedNodes; buildZSortedChildList(chunk, zTranslatedNodes); issueOperationsOf3dChildren(kNegativeZChildren, @@ -910,7 +910,7 @@ void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) { #endif handler(op, saveCountOffset, properties().getClipToBounds()); - if (CC_UNLIKELY(!mProjectedNodes.isEmpty() && projectionReceiveIndex >= 0 && + if (CC_UNLIKELY(!mProjectedNodes.empty() && projectionReceiveIndex >= 0 && opIndex == static_cast(projectionReceiveIndex))) { issueOperationsOfProjectedChildren(renderer, handler); } diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index 4063d4bd53ce..db72287c69c1 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -22,7 +22,6 @@ #include #include #include -#include #include @@ -34,6 +33,8 @@ #include "DisplayList.h" #include "RenderProperties.h" +#include + class SkBitmap; class SkPaint; class SkPath; @@ -176,7 +177,7 @@ public: private: typedef key_value_pair_t ZDrawRenderNodeOpPair; - static size_t findNonNegativeIndex(const Vector& nodes) { + static size_t findNonNegativeIndex(const std::vector& nodes) { for (size_t i = 0; i < nodes.size(); i++) { if (nodes[i].key >= 0.0f) return i; } @@ -190,21 +191,21 @@ private: void computeOrderingImpl(DrawRenderNodeOp* opState, const SkPath* outlineOfProjectionSurface, - Vector* compositedChildrenOfProjectionSurface, + std::vector* compositedChildrenOfProjectionSurface, const mat4* transformFromProjectionSurface); template inline void setViewProperties(OpenGLRenderer& renderer, T& handler); void buildZSortedChildList(const DisplayListData::Chunk& chunk, - Vector& zTranslatedNodes); + std::vector& zTranslatedNodes); template inline void issueDrawShadowOperation(const Matrix4& transformFromParent, T& handler); template inline void issueOperationsOf3dChildren(ChildrenSelectMode mode, - const Matrix4& initialTransform, const Vector& zTranslatedNodes, + const Matrix4& initialTransform, const std::vector& zTranslatedNodes, OpenGLRenderer& renderer, T& handler); template @@ -267,7 +268,7 @@ private: */ // for projection surfaces, contains a list of all children items - Vector mProjectedNodes; + std::vector mProjectedNodes; // How many references our parent(s) have to us. Typically this should alternate // between 2 and 1 (when a staging push happens we inc first then dec) diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp index b6271f63a606..220936551a60 100644 --- a/libs/hwui/ShadowTessellator.cpp +++ b/libs/hwui/ShadowTessellator.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include "AmbientShadow.h" diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp index 17cb3a7fd6fd..01f5e2dba214 100644 --- a/libs/hwui/TessellationCache.cpp +++ b/libs/hwui/TessellationCache.cpp @@ -225,13 +225,13 @@ static void tessellateShadows( VertexBuffer& ambientBuffer, VertexBuffer& spotBuffer) { // tessellate caster outline into a 2d polygon - Vector casterVertices2d; + std::vector casterVertices2d; const float casterRefinementThreshold = 2.0f; PathTessellator::approximatePathOutlineVertices(*casterPerimeter, casterRefinementThreshold, casterVertices2d); // Shadow requires CCW for now. TODO: remove potential double-reverse - reverseVertexArray(casterVertices2d.editArray(), casterVertices2d.size()); + reverseVertexArray(&casterVertices2d.front(), casterVertices2d.size()); if (casterVertices2d.size() == 0) return; @@ -250,7 +250,7 @@ static void tessellateShadows( // map the centroid of the caster into 3d Vector2 centroid = ShadowTessellator::centroid2d( - reinterpret_cast(casterVertices2d.array()), + reinterpret_cast(&casterVertices2d.front()), casterVertexCount); Vector3 centroid3d = {centroid.x, centroid.y, 0}; mapPointFakeZ(centroid3d, casterTransformXY, casterTransformZ); diff --git a/libs/hwui/TessellationCache.h b/libs/hwui/TessellationCache.h index 3efeaf64d486..b54666b7d595 100644 --- a/libs/hwui/TessellationCache.h +++ b/libs/hwui/TessellationCache.h @@ -19,7 +19,6 @@ #include #include -#include #include "Debug.h" #include "utils/Macros.h" diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp index c4467f1856ff..16f6f4ba4bb6 100644 --- a/libs/hwui/TextureCache.cpp +++ b/libs/hwui/TextureCache.cpp @@ -216,14 +216,14 @@ Texture* TextureCache::get(const SkBitmap* bitmap, AtlasUsageType atlasUsageType void TextureCache::releaseTexture(uint32_t pixelRefStableID) { Mutex::Autolock _l(mLock); - mGarbage.push(pixelRefStableID); + mGarbage.push_back(pixelRefStableID); } void TextureCache::clearGarbage() { Mutex::Autolock _l(mLock); size_t count = mGarbage.size(); for (size_t i = 0; i < count; i++) { - uint32_t pixelRefId = mGarbage.itemAt(i); + uint32_t pixelRefId = mGarbage[i]; mCache.remove(pixelRefId); } mGarbage.clear(); diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h index 7a7ee5aeb554..ebd1885e75e1 100644 --- a/libs/hwui/TextureCache.h +++ b/libs/hwui/TextureCache.h @@ -21,10 +21,11 @@ #include #include -#include #include "Debug.h" +#include + namespace android { namespace uirenderer { @@ -165,7 +166,7 @@ private: bool mDebugEnabled; - Vector mGarbage; + std::vector mGarbage; mutable Mutex mLock; AssetAtlas* mAssetAtlas; diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h index 11d0c4bef84f..c1bf980658b2 100644 --- a/libs/hwui/Vertex.h +++ b/libs/hwui/Vertex.h @@ -37,7 +37,6 @@ struct Vertex { */ static float GeometryFudgeFactor() { return 0.0656f; } - float x, y; static inline void set(Vertex* vertex, float x, float y) { diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index f2fa9cdcbefd..88c18a52b872 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -31,7 +31,6 @@ #include #include #include -#include #include #include diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index 5febbe0ab26c..0d2c7be5b317 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -27,7 +27,6 @@ #include #include #include -#include #include "../Caches.h" #include "../IContextFactory.h" diff --git a/libs/hwui/thread/TaskManager.cpp b/libs/hwui/thread/TaskManager.cpp index e9dde294b2aa..a07845ecf659 100644 --- a/libs/hwui/thread/TaskManager.cpp +++ b/libs/hwui/thread/TaskManager.cpp @@ -39,7 +39,7 @@ TaskManager::TaskManager() { for (int i = 0; i < workerCount; i++) { String8 name; name.appendFormat("hwuiTask%d", i + 1); - mThreads.add(new WorkerThread(name)); + mThreads.push_back(new WorkerThread(name)); } } @@ -89,15 +89,14 @@ status_t TaskManager::WorkerThread::readyToRun() { bool TaskManager::WorkerThread::threadLoop() { mSignal.wait(); - Vector tasks; + std::vector tasks; { Mutex::Autolock l(mLock); - tasks = mTasks; - mTasks.clear(); + tasks.swap(mTasks); } for (size_t i = 0; i < tasks.size(); i++) { - const TaskWrapper& task = tasks.itemAt(i); + const TaskWrapper& task = tasks[i]; task.mProcessor->process(task.mTask); } @@ -111,14 +110,13 @@ bool TaskManager::WorkerThread::addTask(TaskWrapper task) { return false; } - ssize_t index; { Mutex::Autolock l(mLock); - index = mTasks.add(task); + mTasks.push_back(task); } mSignal.signal(); - return index >= 0; + return true; } size_t TaskManager::WorkerThread::getTaskCount() const { diff --git a/libs/hwui/thread/TaskManager.h b/libs/hwui/thread/TaskManager.h index 10e8b9e0bead..d0eb3049ae37 100644 --- a/libs/hwui/thread/TaskManager.h +++ b/libs/hwui/thread/TaskManager.h @@ -20,10 +20,11 @@ #include #include #include -#include #include "Signal.h" +#include + namespace android { namespace uirenderer { @@ -89,7 +90,7 @@ private: // Lock for the list of tasks mutable Mutex mLock; - Vector mTasks; + std::vector mTasks; // Signal used to wake up the thread when a new // task is available in the list @@ -98,7 +99,7 @@ private: const String8 mName; }; - Vector > mThreads; + std::vector > mThreads; }; }; // namespace uirenderer -- cgit v1.2.3-59-g8ed1b From 68f5b8a7810a011a068db3390c714bf02f3072c6 Mon Sep 17 00:00:00 2001 From: Chris Craik Date: Wed, 9 Sep 2015 13:23:09 -0700 Subject: Move texture upload behavior to TextureState Change-Id: If1cb32bbc04f437fa0d079084de832de9fd777c2 --- libs/hwui/TextureCache.cpp | 137 +-------------------------------- libs/hwui/TextureCache.h | 12 --- libs/hwui/renderstate/TextureState.cpp | 136 ++++++++++++++++++++++++++++++++ libs/hwui/renderstate/TextureState.h | 12 +++ 4 files changed, 151 insertions(+), 146 deletions(-) (limited to 'libs/hwui/TextureCache.cpp') diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp index 16f6f4ba4bb6..a6c72a380805 100644 --- a/libs/hwui/TextureCache.cpp +++ b/libs/hwui/TextureCache.cpp @@ -16,9 +16,6 @@ #include -#include -#include - #include #include "AssetAtlas.h" @@ -169,7 +166,7 @@ Texture* TextureCache::getCachedTexture(const SkBitmap* bitmap, AtlasUsageType a if (canCache) { texture = new Texture(Caches::getInstance()); texture->bitmapSize = size; - generateTexture(bitmap, texture, false); + Caches::getInstance().textureState().generateTexture(bitmap, texture, false); mSize += size; TEXTURE_LOGD("TextureCache::get: create texture(%p): name, size, mSize = %d, %d, %d", @@ -182,7 +179,7 @@ Texture* TextureCache::getCachedTexture(const SkBitmap* bitmap, AtlasUsageType a } else if (!texture->isInUse && bitmap->getGenerationID() != texture->generation) { // Texture was in the cache but is dirty, re-upload // TODO: Re-adjust the cache size if the bitmap's dimensions have changed - generateTexture(bitmap, texture, true); + Caches::getInstance().textureState().generateTexture(bitmap, texture, true); } return texture; @@ -207,7 +204,7 @@ Texture* TextureCache::get(const SkBitmap* bitmap, AtlasUsageType atlasUsageType const uint32_t size = bitmap->rowBytes() * bitmap->height(); texture = new Texture(Caches::getInstance()); texture->bitmapSize = size; - generateTexture(bitmap, texture, false); + Caches::getInstance().textureState().generateTexture(bitmap, texture, false); texture->cleanup = true; } @@ -249,133 +246,5 @@ void TextureCache::flush() { } } -void TextureCache::generateTexture(const SkBitmap* bitmap, Texture* texture, bool regenerate) { - SkAutoLockPixels alp(*bitmap); - - if (!bitmap->readyToDraw()) { - ALOGE("Cannot generate texture from bitmap"); - return; - } - - ATRACE_FORMAT("Upload %ux%u Texture", bitmap->width(), bitmap->height()); - - // We could also enable mipmapping if both bitmap dimensions are powers - // of 2 but we'd have to deal with size changes. Let's keep this simple - const bool canMipMap = Caches::getInstance().extensions().hasNPot(); - - // If the texture had mipmap enabled but not anymore, - // force a glTexImage2D to discard the mipmap levels - const bool resize = !regenerate || bitmap->width() != int(texture->width) || - bitmap->height() != int(texture->height) || - (regenerate && canMipMap && texture->mipMap && !bitmap->hasHardwareMipMap()); - - if (!regenerate) { - glGenTextures(1, &texture->id); - } - - texture->generation = bitmap->getGenerationID(); - texture->width = bitmap->width(); - texture->height = bitmap->height(); - - Caches::getInstance().textureState().bindTexture(texture->id); - - switch (bitmap->colorType()) { - case kAlpha_8_SkColorType: - uploadToTexture(resize, GL_ALPHA, bitmap->rowBytesAsPixels(), bitmap->bytesPerPixel(), - texture->width, texture->height, GL_UNSIGNED_BYTE, bitmap->getPixels()); - texture->blend = true; - break; - case kRGB_565_SkColorType: - uploadToTexture(resize, GL_RGB, bitmap->rowBytesAsPixels(), bitmap->bytesPerPixel(), - texture->width, texture->height, GL_UNSIGNED_SHORT_5_6_5, bitmap->getPixels()); - texture->blend = false; - break; - case kN32_SkColorType: - uploadToTexture(resize, GL_RGBA, bitmap->rowBytesAsPixels(), bitmap->bytesPerPixel(), - texture->width, texture->height, GL_UNSIGNED_BYTE, bitmap->getPixels()); - // Do this after calling getPixels() to make sure Skia's deferred - // decoding happened - texture->blend = !bitmap->isOpaque(); - break; - case kARGB_4444_SkColorType: - case kIndex_8_SkColorType: - uploadLoFiTexture(resize, bitmap, texture->width, texture->height); - texture->blend = !bitmap->isOpaque(); - break; - default: - ALOGW("Unsupported bitmap colorType: %d", bitmap->colorType()); - break; - } - - if (canMipMap) { - texture->mipMap = bitmap->hasHardwareMipMap(); - if (texture->mipMap) { - glGenerateMipmap(GL_TEXTURE_2D); - } - } - - if (!regenerate) { - texture->setFilter(GL_NEAREST); - texture->setWrap(GL_CLAMP_TO_EDGE); - } -} - -void TextureCache::uploadLoFiTexture(bool resize, const SkBitmap* bitmap, - uint32_t width, uint32_t height) { - SkBitmap rgbaBitmap; - rgbaBitmap.allocPixels(SkImageInfo::MakeN32(width, height, bitmap->alphaType())); - rgbaBitmap.eraseColor(0); - - SkCanvas canvas(rgbaBitmap); - canvas.drawBitmap(*bitmap, 0.0f, 0.0f, nullptr); - - uploadToTexture(resize, GL_RGBA, rgbaBitmap.rowBytesAsPixels(), rgbaBitmap.bytesPerPixel(), - width, height, GL_UNSIGNED_BYTE, rgbaBitmap.getPixels()); -} - -void TextureCache::uploadToTexture(bool resize, GLenum format, GLsizei stride, GLsizei bpp, - GLsizei width, GLsizei height, GLenum type, const GLvoid * data) { - glPixelStorei(GL_UNPACK_ALIGNMENT, bpp); - const bool useStride = stride != width - && Caches::getInstance().extensions().hasUnpackRowLength(); - if ((stride == width) || useStride) { - if (useStride) { - glPixelStorei(GL_UNPACK_ROW_LENGTH, stride); - } - - if (resize) { - glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data); - } else { - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data); - } - - if (useStride) { - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - } - } else { - // With OpenGL ES 2.0 we need to copy the bitmap in a temporary buffer - // if the stride doesn't match the width - - GLvoid * temp = (GLvoid *) malloc(width * height * bpp); - if (!temp) return; - - uint8_t * pDst = (uint8_t *)temp; - uint8_t * pSrc = (uint8_t *)data; - for (GLsizei i = 0; i < height; i++) { - memcpy(pDst, pSrc, width * bpp); - pDst += width * bpp; - pSrc += stride * bpp; - } - - if (resize) { - glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, temp); - } else { - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, temp); - } - - free(temp); - } -} - }; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h index ebd1885e75e1..191c8a81fec6 100644 --- a/libs/hwui/TextureCache.h +++ b/libs/hwui/TextureCache.h @@ -144,18 +144,6 @@ private: Texture* get(const SkBitmap* bitmap, AtlasUsageType atlasUsageType); Texture* getCachedTexture(const SkBitmap* bitmap, AtlasUsageType atlasUsageType); - /** - * Generates the texture from a bitmap into the specified texture structure. - * - * @param regenerate If true, the bitmap data is reuploaded into the texture, but - * no new texture is generated. - */ - void generateTexture(const SkBitmap* bitmap, Texture* texture, bool regenerate = false); - - void uploadLoFiTexture(bool resize, const SkBitmap* bitmap, uint32_t width, uint32_t height); - void uploadToTexture(bool resize, GLenum format, GLsizei stride, GLsizei bpp, - GLsizei width, GLsizei height, GLenum type, const GLvoid * data); - LruCache mCache; uint32_t mSize; diff --git a/libs/hwui/renderstate/TextureState.cpp b/libs/hwui/renderstate/TextureState.cpp index 987d4cd55a5e..1f50f712c267 100644 --- a/libs/hwui/renderstate/TextureState.cpp +++ b/libs/hwui/renderstate/TextureState.cpp @@ -15,6 +15,14 @@ */ #include "renderstate/TextureState.h" +#include "Caches.h" +#include "utils/TraceUtils.h" + +#include +#include +#include +#include + namespace android { namespace uirenderer { @@ -26,6 +34,134 @@ const GLenum kTextureUnits[] = { GL_TEXTURE3 }; +static void uploadToTexture(bool resize, GLenum format, GLenum type, GLsizei stride, GLsizei bpp, + GLsizei width, GLsizei height, const GLvoid * data) { + + glPixelStorei(GL_UNPACK_ALIGNMENT, bpp); + const bool useStride = stride != width + && Caches::getInstance().extensions().hasUnpackRowLength(); + if ((stride == width) || useStride) { + if (useStride) { + glPixelStorei(GL_UNPACK_ROW_LENGTH, stride); + } + + if (resize) { + glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data); + } else { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data); + } + + if (useStride) { + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + } + } else { + // With OpenGL ES 2.0 we need to copy the bitmap in a temporary buffer + // if the stride doesn't match the width + + GLvoid * temp = (GLvoid *) malloc(width * height * bpp); + if (!temp) return; + + uint8_t * pDst = (uint8_t *)temp; + uint8_t * pSrc = (uint8_t *)data; + for (GLsizei i = 0; i < height; i++) { + memcpy(pDst, pSrc, width * bpp); + pDst += width * bpp; + pSrc += stride * bpp; + } + + if (resize) { + glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, temp); + } else { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, temp); + } + + free(temp); + } +} + +static void uploadSkBitmapToTexture(const SkBitmap& bitmap, + bool resize, GLenum format, GLenum type) { + uploadToTexture(resize, format, type, bitmap.rowBytesAsPixels(), bitmap.bytesPerPixel(), + bitmap.width(), bitmap.height(), bitmap.getPixels()); +} + +void TextureState::generateTexture(const SkBitmap* bitmap, Texture* texture, bool regenerate) { + SkAutoLockPixels alp(*bitmap); + + if (!bitmap->readyToDraw()) { + ALOGE("Cannot generate texture from bitmap"); + return; + } + + ATRACE_FORMAT("Upload %ux%u Texture", bitmap->width(), bitmap->height()); + + // We could also enable mipmapping if both bitmap dimensions are powers + // of 2 but we'd have to deal with size changes. Let's keep this simple + const bool canMipMap = Caches::getInstance().extensions().hasNPot(); + + // If the texture had mipmap enabled but not anymore, + // force a glTexImage2D to discard the mipmap levels + const bool resize = !regenerate || bitmap->width() != int(texture->width) || + bitmap->height() != int(texture->height) || + (regenerate && canMipMap && texture->mipMap && !bitmap->hasHardwareMipMap()); + + if (!regenerate) { + glGenTextures(1, &texture->id); + } + + texture->generation = bitmap->getGenerationID(); + texture->width = bitmap->width(); + texture->height = bitmap->height(); + + bindTexture(texture->id); + + switch (bitmap->colorType()) { + case kAlpha_8_SkColorType: + uploadSkBitmapToTexture(*bitmap, resize, GL_ALPHA, GL_UNSIGNED_BYTE); + texture->blend = true; + break; + case kRGB_565_SkColorType: + uploadSkBitmapToTexture(*bitmap, resize, GL_RGB, GL_UNSIGNED_SHORT_5_6_5); + texture->blend = false; + break; + case kN32_SkColorType: + uploadSkBitmapToTexture(*bitmap, resize, GL_RGBA, GL_UNSIGNED_BYTE); + // Do this after calling getPixels() to make sure Skia's deferred + // decoding happened + texture->blend = !bitmap->isOpaque(); + break; + case kARGB_4444_SkColorType: + case kIndex_8_SkColorType: { + SkBitmap rgbaBitmap; + rgbaBitmap.allocPixels(SkImageInfo::MakeN32(texture->width, texture->height, + bitmap->alphaType())); + rgbaBitmap.eraseColor(0); + + SkCanvas canvas(rgbaBitmap); + canvas.drawBitmap(*bitmap, 0.0f, 0.0f, nullptr); + + uploadSkBitmapToTexture(rgbaBitmap, resize, GL_RGBA, GL_UNSIGNED_BYTE); + texture->blend = !bitmap->isOpaque(); + break; + } + default: + ALOGW("Unsupported bitmap colorType: %d", bitmap->colorType()); + break; + } + + if (canMipMap) { + texture->mipMap = bitmap->hasHardwareMipMap(); + if (texture->mipMap) { + glGenerateMipmap(GL_TEXTURE_2D); + } + } + + if (!regenerate) { + texture->setFilter(GL_NEAREST); + texture->setWrap(GL_CLAMP_TO_EDGE); + } +} + TextureState::TextureState() : mTextureUnit(0) { glActiveTexture(kTextureUnits[0]); diff --git a/libs/hwui/renderstate/TextureState.h b/libs/hwui/renderstate/TextureState.h index d3c014c00bce..3a2b85ae2886 100644 --- a/libs/hwui/renderstate/TextureState.h +++ b/libs/hwui/renderstate/TextureState.h @@ -23,9 +23,13 @@ #include #include +class SkBitmap; + namespace android { namespace uirenderer { +class Texture; + class TextureState { friend class Caches; // TODO: move to RenderState public: @@ -71,6 +75,14 @@ public: * Clear the cache of bound textures. */ void unbindTexture(GLuint texture); + + /** + * Generates the texture from a bitmap into the specified texture structure. + * + * @param regenerate If true, the bitmap data is reuploaded into the texture, but + * no new texture is generated. + */ + void generateTexture(const SkBitmap* bitmap, Texture* texture, bool regenerate); private: // total number of texture units available for use static const int kTextureUnitsCount = 4; -- cgit v1.2.3-59-g8ed1b From 15c3f19a445b8df575911a16e8a6dba755a084b5 Mon Sep 17 00:00:00 2001 From: Chris Craik Date: Thu, 3 Dec 2015 12:16:56 -0800 Subject: Merged op dispatch in OpReorderer bug:22480459 Also switches std::functions to function pointers on OpReorderer, and switches AssetAtlas' entry getter methods to using pixelRef pointers, so it's clear they're the keys. Change-Id: I3040ce5ff4e178a8364e0fd7ab0876ada7d4de05 --- libs/hwui/AssetAtlas.cpp | 8 +- libs/hwui/AssetAtlas.h | 8 +- libs/hwui/BakedOpDispatcher.cpp | 252 ++++++++++++++------- libs/hwui/BakedOpDispatcher.h | 15 +- libs/hwui/BakedOpRenderer.cpp | 27 ++- libs/hwui/BakedOpRenderer.h | 11 +- libs/hwui/BakedOpState.h | 10 + libs/hwui/ClipArea.cpp | 2 +- libs/hwui/DisplayListOp.h | 4 +- libs/hwui/FontRenderer.cpp | 3 +- libs/hwui/FontRenderer.h | 3 + libs/hwui/GlopBuilder.h | 2 +- libs/hwui/OpReorderer.cpp | 88 +++++-- libs/hwui/OpReorderer.h | 56 +++-- libs/hwui/OpenGLRenderer.cpp | 8 +- libs/hwui/PathTessellator.cpp | 6 +- libs/hwui/RecordedOp.h | 35 ++- libs/hwui/RecordingCanvas.cpp | 6 +- libs/hwui/Rect.h | 13 +- libs/hwui/TextureCache.cpp | 2 +- libs/hwui/VertexBuffer.h | 2 +- libs/hwui/tests/common/TestUtils.h | 5 +- .../hwui/tests/common/scenes/ListViewAnimation.cpp | 12 +- libs/hwui/tests/microbench/OpReordererBench.cpp | 2 +- libs/hwui/tests/unit/OpReordererTests.cpp | 41 +++- 25 files changed, 425 insertions(+), 196 deletions(-) (limited to 'libs/hwui/TextureCache.cpp') diff --git a/libs/hwui/AssetAtlas.cpp b/libs/hwui/AssetAtlas.cpp index 7e0969916825..41411a98a4bf 100644 --- a/libs/hwui/AssetAtlas.cpp +++ b/libs/hwui/AssetAtlas.cpp @@ -79,13 +79,13 @@ void AssetAtlas::updateTextureId() { // Entries /////////////////////////////////////////////////////////////////////////////// -AssetAtlas::Entry* AssetAtlas::getEntry(const SkBitmap* bitmap) const { - ssize_t index = mEntries.indexOfKey(bitmap->pixelRef()); +AssetAtlas::Entry* AssetAtlas::getEntry(const SkPixelRef* pixelRef) const { + ssize_t index = mEntries.indexOfKey(pixelRef); return index >= 0 ? mEntries.valueAt(index) : nullptr; } -Texture* AssetAtlas::getEntryTexture(const SkBitmap* bitmap) const { - ssize_t index = mEntries.indexOfKey(bitmap->pixelRef()); +Texture* AssetAtlas::getEntryTexture(const SkPixelRef* pixelRef) const { + ssize_t index = mEntries.indexOfKey(pixelRef); return index >= 0 ? mEntries.valueAt(index)->texture : nullptr; } diff --git a/libs/hwui/AssetAtlas.h b/libs/hwui/AssetAtlas.h index f1cd0b4947dc..a037725b1c6c 100644 --- a/libs/hwui/AssetAtlas.h +++ b/libs/hwui/AssetAtlas.h @@ -148,15 +148,15 @@ public: /** * Returns the entry in the atlas associated with the specified - * bitmap. If the bitmap is not in the atlas, return NULL. + * pixelRef. If the pixelRef is not in the atlas, return NULL. */ - Entry* getEntry(const SkBitmap* bitmap) const; + Entry* getEntry(const SkPixelRef* pixelRef) const; /** * Returns the texture for the atlas entry associated with the - * specified bitmap. If the bitmap is not in the atlas, return NULL. + * specified pixelRef. If the pixelRef is not in the atlas, return NULL. */ - Texture* getEntryTexture(const SkBitmap* bitmap) const; + Texture* getEntryTexture(const SkPixelRef* pixelRef) const; private: void createEntries(Caches& caches, int64_t* map, int count); diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp index b56b1e4c5f93..fde12dd261f5 100644 --- a/libs/hwui/BakedOpDispatcher.cpp +++ b/libs/hwui/BakedOpDispatcher.cpp @@ -31,20 +31,182 @@ namespace android { namespace uirenderer { +static void storeTexturedRect(TextureVertex* vertices, const Rect& bounds, const Rect& texCoord) { + vertices[0] = { bounds.left, bounds.top, texCoord.left, texCoord.top }; + vertices[1] = { bounds.right, bounds.top, texCoord.right, texCoord.top }; + vertices[2] = { bounds.left, bounds.bottom, texCoord.left, texCoord.bottom }; + vertices[3] = { bounds.right, bounds.bottom, texCoord.right, texCoord.bottom }; +} + +void BakedOpDispatcher::onMergedBitmapOps(BakedOpRenderer& renderer, + const MergedBakedOpList& opList) { + + const BakedOpState& firstState = *(opList.states[0]); + const SkBitmap* bitmap = (static_cast(opList.states[0]->op))->bitmap; + + AssetAtlas::Entry* entry = renderer.renderState().assetAtlas().getEntry(bitmap->pixelRef()); + Texture* texture = entry ? entry->texture : renderer.caches().textureCache.get(bitmap); + if (!texture) return; + const AutoTexture autoCleanup(texture); + + TextureVertex vertices[opList.count * 4]; + Rect texCoords(0, 0, 1, 1); + if (entry) { + entry->uvMapper.map(texCoords); + } + // init to non-empty, so we can safely expandtoCoverRect + Rect totalBounds = firstState.computedState.clippedBounds; + for (size_t i = 0; i < opList.count; i++) { + const BakedOpState& state = *(opList.states[i]); + TextureVertex* rectVerts = &vertices[i * 4]; + Rect opBounds = state.computedState.clippedBounds; + if (CC_LIKELY(state.computedState.transform.isPureTranslate())) { + // pure translate, so snap (same behavior as onBitmapOp) + opBounds.snapToPixelBoundaries(); + } + storeTexturedRect(rectVerts, opBounds, texCoords); + renderer.dirtyRenderTarget(opBounds); + + totalBounds.expandToCover(opBounds); + } + + const int textureFillFlags = (bitmap->colorType() == kAlpha_8_SkColorType) + ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None; + Glop glop; + GlopBuilder(renderer.renderState(), renderer.caches(), &glop) + .setRoundRectClipState(firstState.roundRectClipState) + .setMeshTexturedIndexedQuads(vertices, opList.count * 6) + .setFillTexturePaint(*texture, textureFillFlags, firstState.op->paint, firstState.alpha) + .setTransform(Matrix4::identity(), TransformFlags::None) + .setModelViewOffsetRect(0, 0, totalBounds) // don't snap here, we snap per-quad above + .build(); + renderer.renderGlop(nullptr, opList.clipSideFlags ? &opList.clip : nullptr, glop); +} + +static void renderTextShadow(BakedOpRenderer& renderer, FontRenderer& fontRenderer, + const TextOp& op, const BakedOpState& state) { + renderer.caches().textureState().activateTexture(0); + + PaintUtils::TextShadow textShadow; + if (!PaintUtils::getTextShadow(op.paint, &textShadow)) { + LOG_ALWAYS_FATAL("failed to query shadow attributes"); + } + + renderer.caches().dropShadowCache.setFontRenderer(fontRenderer); + ShadowTexture* texture = renderer.caches().dropShadowCache.get( + op.paint, (const char*) op.glyphs, + op.glyphCount, textShadow.radius, op.positions); + // If the drop shadow exceeds the max texture size or couldn't be + // allocated, skip drawing + if (!texture) return; + const AutoTexture autoCleanup(texture); + + const float sx = op.x - texture->left + textShadow.dx; + const float sy = op.y - texture->top + textShadow.dy; + + Glop glop; + GlopBuilder(renderer.renderState(), renderer.caches(), &glop) + .setRoundRectClipState(state.roundRectClipState) + .setMeshTexturedUnitQuad(nullptr) + .setFillShadowTexturePaint(*texture, textShadow.color, *op.paint, state.alpha) + .setTransform(state.computedState.transform, TransformFlags::None) + .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width, sy + texture->height)) + .build(); + renderer.renderGlop(state, glop); +} + +enum class TextRenderType { + Defer, + Flush +}; + +static void renderTextOp(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state, + const Rect* renderClip, TextRenderType renderType) { + FontRenderer& fontRenderer = renderer.caches().fontRenderer.getFontRenderer(); + + if (CC_UNLIKELY(PaintUtils::hasTextShadow(op.paint))) { + fontRenderer.setFont(op.paint, SkMatrix::I()); + renderTextShadow(renderer, fontRenderer, op, state); + } + + float x = op.x; + float y = op.y; + const Matrix4& transform = state.computedState.transform; + const bool pureTranslate = transform.isPureTranslate(); + if (CC_LIKELY(pureTranslate)) { + x = floorf(x + transform.getTranslateX() + 0.5f); + y = floorf(y + transform.getTranslateY() + 0.5f); + fontRenderer.setFont(op.paint, SkMatrix::I()); + fontRenderer.setTextureFiltering(false); + } else if (CC_UNLIKELY(transform.isPerspective())) { + fontRenderer.setFont(op.paint, SkMatrix::I()); + fontRenderer.setTextureFiltering(true); + } else { + // We only pass a partial transform to the font renderer. That partial + // matrix defines how glyphs are rasterized. Typically we want glyphs + // to be rasterized at their final size on screen, which means the partial + // matrix needs to take the scale factor into account. + // When a partial matrix is used to transform glyphs during rasterization, + // the mesh is generated with the inverse transform (in the case of scale, + // the mesh is generated at 1.0 / scale for instance.) This allows us to + // apply the full transform matrix at draw time in the vertex shader. + // Applying the full matrix in the shader is the easiest way to handle + // rotation and perspective and allows us to always generated quads in the + // font renderer which greatly simplifies the code, clipping in particular. + float sx, sy; + transform.decomposeScale(sx, sy); + fontRenderer.setFont(op.paint, SkMatrix::MakeScale( + roundf(std::max(1.0f, sx)), + roundf(std::max(1.0f, sy)))); + fontRenderer.setTextureFiltering(true); + } + Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); + + int alpha = PaintUtils::getAlphaDirect(op.paint) * state.alpha; + SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(op.paint); + TextDrawFunctor functor(&renderer, &state, renderClip, + x, y, pureTranslate, alpha, mode, op.paint); + + bool forceFinish = (renderType == TextRenderType::Flush); + bool mustDirtyRenderTarget = renderer.offscreenRenderTarget(); + const Rect* localOpClip = pureTranslate ? &state.computedState.clipRect : nullptr; + fontRenderer.renderPosText(op.paint, localOpClip, + (const char*) op.glyphs, op.glyphCount, x, y, + op.positions, mustDirtyRenderTarget ? &layerBounds : nullptr, &functor, forceFinish); + + if (mustDirtyRenderTarget) { + if (!pureTranslate) { + transform.mapRect(layerBounds); + } + renderer.dirtyRenderTarget(layerBounds); + } +} + +void BakedOpDispatcher::onMergedTextOps(BakedOpRenderer& renderer, + const MergedBakedOpList& opList) { + const Rect* clip = opList.clipSideFlags ? &opList.clip : nullptr; + for (size_t i = 0; i < opList.count; i++) { + const BakedOpState& state = *(opList.states[i]); + const TextOp& op = *(static_cast(state.op)); + TextRenderType renderType = (i + 1 == opList.count) + ? TextRenderType::Flush : TextRenderType::Defer; + renderTextOp(renderer, op, state, clip, renderType); + } +} + void BakedOpDispatcher::onRenderNodeOp(BakedOpRenderer&, const RenderNodeOp&, const BakedOpState&) { LOG_ALWAYS_FATAL("unsupported operation"); } -void BakedOpDispatcher::onBeginLayerOp(BakedOpRenderer& renderer, const BeginLayerOp& op, const BakedOpState& state) { +void BakedOpDispatcher::onBeginLayerOp(BakedOpRenderer&, const BeginLayerOp&, const BakedOpState&) { LOG_ALWAYS_FATAL("unsupported operation"); } -void BakedOpDispatcher::onEndLayerOp(BakedOpRenderer& renderer, const EndLayerOp& op, const BakedOpState& state) { +void BakedOpDispatcher::onEndLayerOp(BakedOpRenderer&, const EndLayerOp&, const BakedOpState&) { LOG_ALWAYS_FATAL("unsupported operation"); } void BakedOpDispatcher::onBitmapOp(BakedOpRenderer& renderer, const BitmapOp& op, const BakedOpState& state) { - renderer.caches().textureState().activateTexture(0); // TODO: should this be automatic, and/or elsewhere? Texture* texture = renderer.getTexture(op.bitmap); if (!texture) return; const AutoTexture autoCleanup(texture); @@ -153,89 +315,9 @@ void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleR renderer.renderGlop(state, glop); } -static void renderTextShadow(BakedOpRenderer& renderer, FontRenderer& fontRenderer, - const TextOp& op, const BakedOpState& state) { - renderer.caches().textureState().activateTexture(0); - - PaintUtils::TextShadow textShadow; - if (!PaintUtils::getTextShadow(op.paint, &textShadow)) { - LOG_ALWAYS_FATAL("failed to query shadow attributes"); - } - - renderer.caches().dropShadowCache.setFontRenderer(fontRenderer); - ShadowTexture* texture = renderer.caches().dropShadowCache.get( - op.paint, (const char*) op.glyphs, - op.glyphCount, textShadow.radius, op.positions); - // If the drop shadow exceeds the max texture size or couldn't be - // allocated, skip drawing - if (!texture) return; - const AutoTexture autoCleanup(texture); - - const float sx = op.x - texture->left + textShadow.dx; - const float sy = op.y - texture->top + textShadow.dy; - - Glop glop; - GlopBuilder(renderer.renderState(), renderer.caches(), &glop) - .setRoundRectClipState(state.roundRectClipState) - .setMeshTexturedUnitQuad(nullptr) - .setFillShadowTexturePaint(*texture, textShadow.color, *op.paint, state.alpha) - .setTransform(state.computedState.transform, TransformFlags::None) - .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width, sy + texture->height)) - .build(); - renderer.renderGlop(state, glop); -} - void BakedOpDispatcher::onTextOp(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state) { - FontRenderer& fontRenderer = renderer.caches().fontRenderer.getFontRenderer(); - - if (CC_UNLIKELY(PaintUtils::hasTextShadow(op.paint))) { - fontRenderer.setFont(op.paint, SkMatrix::I()); - renderTextShadow(renderer, fontRenderer, op, state); - } - - float x = op.x; - float y = op.y; - const Matrix4& transform = state.computedState.transform; - const bool pureTranslate = transform.isPureTranslate(); - if (CC_LIKELY(pureTranslate)) { - x = floorf(x + transform.getTranslateX() + 0.5f); - y = floorf(y + transform.getTranslateY() + 0.5f); - fontRenderer.setFont(op.paint, SkMatrix::I()); - fontRenderer.setTextureFiltering(false); - } else if (CC_UNLIKELY(transform.isPerspective())) { - fontRenderer.setFont(op.paint, SkMatrix::I()); - fontRenderer.setTextureFiltering(true); - } else { - // We only pass a partial transform to the font renderer. That partial - // matrix defines how glyphs are rasterized. Typically we want glyphs - // to be rasterized at their final size on screen, which means the partial - // matrix needs to take the scale factor into account. - // When a partial matrix is used to transform glyphs during rasterization, - // the mesh is generated with the inverse transform (in the case of scale, - // the mesh is generated at 1.0 / scale for instance.) This allows us to - // apply the full transform matrix at draw time in the vertex shader. - // Applying the full matrix in the shader is the easiest way to handle - // rotation and perspective and allows us to always generated quads in the - // font renderer which greatly simplifies the code, clipping in particular. - float sx, sy; - transform.decomposeScale(sx, sy); - fontRenderer.setFont(op.paint, SkMatrix::MakeScale( - roundf(std::max(1.0f, sx)), - roundf(std::max(1.0f, sy)))); - fontRenderer.setTextureFiltering(true); - } - - // TODO: Implement better clipping for scaled/rotated text - const Rect* clip = !pureTranslate ? nullptr : &state.computedState.clipRect; - Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); - - int alpha = PaintUtils::getAlphaDirect(op.paint) * state.alpha; - SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(op.paint); - TextDrawFunctor functor(&renderer, &state, x, y, pureTranslate, alpha, mode, op.paint); - - bool hasActiveLayer = false; // TODO - fontRenderer.renderPosText(op.paint, clip, (const char*) op.glyphs, op.glyphCount, x, y, - op.positions, hasActiveLayer ? &layerBounds : nullptr, &functor, true); // TODO: merging + const Rect* clip = state.computedState.clipSideFlags ? &state.computedState.clipRect : nullptr; + renderTextOp(renderer, op, state, clip, TextRenderType::Flush); } void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op, const BakedOpState& state) { diff --git a/libs/hwui/BakedOpDispatcher.h b/libs/hwui/BakedOpDispatcher.h index caf14bfeef6d..0e763d9c660b 100644 --- a/libs/hwui/BakedOpDispatcher.h +++ b/libs/hwui/BakedOpDispatcher.h @@ -26,16 +26,21 @@ namespace uirenderer { /** * Provides all "onBitmapOp(...)" style static methods for every op type, which convert the * RecordedOps and their state to Glops, and renders them with the provided BakedOpRenderer. - * - * This dispatcher is separate from the renderer so that the dispatcher / renderer interaction is - * minimal through public BakedOpRenderer APIs. */ class BakedOpDispatcher { public: + // Declares all "onMergedBitmapOps(...)" style methods for mergeable op types +#define X(Type) \ + static void onMerged##Type##s(BakedOpRenderer& renderer, const MergedBakedOpList& opList); + MAP_MERGED_OPS(X) +#undef X + // Declares all "onBitmapOp(...)" style methods for every op type -#define DISPATCH_METHOD(Type) \ +#define X(Type) \ static void on##Type(BakedOpRenderer& renderer, const Type& op, const BakedOpState& state); - MAP_OPS(DISPATCH_METHOD); + MAP_OPS(X) +#undef X + }; }; // namespace uirenderer diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp index 6cdc320a0bad..93a9406da7bc 100644 --- a/libs/hwui/BakedOpRenderer.cpp +++ b/libs/hwui/BakedOpRenderer.cpp @@ -121,30 +121,35 @@ void BakedOpRenderer::clearColorBuffer(const Rect& rect) { } Texture* BakedOpRenderer::getTexture(const SkBitmap* bitmap) { - Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap); + Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap->pixelRef()); if (!texture) { return mCaches.textureCache.get(bitmap); } return texture; } -void BakedOpRenderer::renderGlop(const BakedOpState& state, const Glop& glop) { - bool useScissor = state.computedState.clipSideFlags != OpClipSideFlags::None; - mRenderState.scissor().setEnabled(useScissor); - if (useScissor) { - const Rect& clip = state.computedState.clipRect; - mRenderState.scissor().set(clip.left, mRenderTarget.viewportHeight - clip.bottom, - clip.getWidth(), clip.getHeight()); +void BakedOpRenderer::renderGlop(const Rect* dirtyBounds, const Rect* clip, const Glop& glop) { + mRenderState.scissor().setEnabled(clip != nullptr); + if (clip) { + mRenderState.scissor().set(clip->left, mRenderTarget.viewportHeight - clip->bottom, + clip->getWidth(), clip->getHeight()); } - if (mRenderTarget.offscreenBuffer) { // TODO: not with multi-draw + if (dirtyBounds && mRenderTarget.offscreenBuffer) { // register layer damage to draw-back region - const Rect& uiDirty = state.computedState.clippedBounds; - android::Rect dirty(uiDirty.left, uiDirty.top, uiDirty.right, uiDirty.bottom); + android::Rect dirty(dirtyBounds->left, dirtyBounds->top, + dirtyBounds->right, dirtyBounds->bottom); mRenderTarget.offscreenBuffer->region.orSelf(dirty); } mRenderState.render(glop, mRenderTarget.orthoMatrix); if (!mRenderTarget.frameBufferId) mHasDrawn = true; } +void BakedOpRenderer::dirtyRenderTarget(const Rect& uiDirty) { + if (mRenderTarget.offscreenBuffer) { + android::Rect dirty(uiDirty.left, uiDirty.top, uiDirty.right, uiDirty.bottom); + mRenderTarget.offscreenBuffer->region.orSelf(dirty); + } +} + } // namespace uirenderer } // namespace android diff --git a/libs/hwui/BakedOpRenderer.h b/libs/hwui/BakedOpRenderer.h index 62d183846e27..d7600db0e255 100644 --- a/libs/hwui/BakedOpRenderer.h +++ b/libs/hwui/BakedOpRenderer.h @@ -67,7 +67,16 @@ public: Texture* getTexture(const SkBitmap* bitmap); const LightInfo& getLightInfo() { return mLightInfo; } - void renderGlop(const BakedOpState& state, const Glop& glop); + void renderGlop(const BakedOpState& state, const Glop& glop) { + bool useScissor = state.computedState.clipSideFlags != OpClipSideFlags::None; + renderGlop(&state.computedState.clippedBounds, + useScissor ? &state.computedState.clipRect : nullptr, + glop); + } + + void renderGlop(const Rect* dirtyBounds, const Rect* clip, const Glop& glop); + bool offscreenRenderTarget() { return mRenderTarget.offscreenBuffer != nullptr; } + void dirtyRenderTarget(const Rect& dirtyRect); bool didDraw() { return mHasDrawn; } private: void setViewport(uint32_t width, uint32_t height); diff --git a/libs/hwui/BakedOpState.h b/libs/hwui/BakedOpState.h index 9a40c3b3d3b0..983c27b4a511 100644 --- a/libs/hwui/BakedOpState.h +++ b/libs/hwui/BakedOpState.h @@ -37,6 +37,16 @@ namespace OpClipSideFlags { }; } +/** + * Holds a list of BakedOpStates of ops that can be drawn together + */ +struct MergedBakedOpList { + const BakedOpState*const* states; + size_t count; + int clipSideFlags; + Rect clip; +}; + /** * Holds the resolved clip, transform, and bounds of a recordedOp, when replayed with a snapshot */ diff --git a/libs/hwui/ClipArea.cpp b/libs/hwui/ClipArea.cpp index a9d1e4284d2e..fd6f0b5739d2 100644 --- a/libs/hwui/ClipArea.cpp +++ b/libs/hwui/ClipArea.cpp @@ -26,7 +26,7 @@ namespace uirenderer { static void handlePoint(Rect& transformedBounds, const Matrix4& transform, float x, float y) { Vertex v = {x, y}; transform.mapPoint(v.x, v.y); - transformedBounds.expandToCoverVertex(v.x, v.y); + transformedBounds.expandToCover(v.x, v.y); } Rect transformAndCalculateBounds(const Rect& r, const Matrix4& transform) { diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h index e7cc464facd8..92217edc2f16 100644 --- a/libs/hwui/DisplayListOp.h +++ b/libs/hwui/DisplayListOp.h @@ -612,7 +612,7 @@ public: AssetAtlas::Entry* getAtlasEntry(OpenGLRenderer& renderer) { if (!mEntryValid) { mEntryValid = true; - mEntry = renderer.renderState().assetAtlas().getEntry(mBitmap); + mEntry = renderer.renderState().assetAtlas().getEntry(mBitmap->pixelRef()); } return mEntry; } @@ -777,7 +777,7 @@ public: AssetAtlas::Entry* getAtlasEntry(OpenGLRenderer& renderer) { if (!mEntryValid) { mEntryValid = true; - mEntry = renderer.renderState().assetAtlas().getEntry(mBitmap); + mEntry = renderer.renderState().assetAtlas().getEntry(mBitmap->pixelRef()); } return mEntry; } diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index 47654f400ec2..9c8649fc9775 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -75,7 +75,8 @@ void TextDrawFunctor::draw(CacheTexture& texture, bool linearFiltering) { .setTransform(bakedState->computedState.transform, transformFlags) .setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0)) .build(); - renderer->renderGlop(*bakedState, glop); + // Note: don't pass dirty bounds here, so user must manage passing dirty bounds to renderer + renderer->renderGlop(nullptr, clip, glop); #else GlopBuilder(renderer->mRenderState, renderer->mCaches, &glop) .setRoundRectClipState(renderer->currentSnapshot()->roundRectClipState) diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h index 87cfe7ff98e0..ff4dc4aef94a 100644 --- a/libs/hwui/FontRenderer.h +++ b/libs/hwui/FontRenderer.h @@ -57,6 +57,7 @@ public: #if HWUI_NEW_OPS BakedOpRenderer* renderer, const BakedOpState* bakedState, + const Rect* clip, #else OpenGLRenderer* renderer, #endif @@ -65,6 +66,7 @@ public: : renderer(renderer) #if HWUI_NEW_OPS , bakedState(bakedState) + , clip(clip) #endif , x(x) , y(y) @@ -79,6 +81,7 @@ public: #if HWUI_NEW_OPS BakedOpRenderer* renderer; const BakedOpState* bakedState; + const Rect* clip; #else OpenGLRenderer* renderer; #endif diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h index 6270dcbe7a84..b647b90a62e0 100644 --- a/libs/hwui/GlopBuilder.h +++ b/libs/hwui/GlopBuilder.h @@ -53,7 +53,7 @@ public: GlopBuilder& setMeshTexturedUvQuad(const UvMapper* uvMapper, const Rect uvs); GlopBuilder& setMeshVertexBuffer(const VertexBuffer& vertexBuffer, bool shadowInterp); GlopBuilder& setMeshIndexedQuads(Vertex* vertexData, int quadCount); - GlopBuilder& setMeshTexturedMesh(TextureVertex* vertexData, int elementCount); // TODO: use indexed quads + GlopBuilder& setMeshTexturedMesh(TextureVertex* vertexData, int elementCount); // TODO: delete GlopBuilder& setMeshColoredTexturedMesh(ColorTextureVertex* vertexData, int elementCount); // TODO: use indexed quads GlopBuilder& setMeshTexturedIndexedQuads(TextureVertex* vertexData, int elementCount); // TODO: take quadCount GlopBuilder& setMeshPatchQuads(const Patch& patch); diff --git a/libs/hwui/OpReorderer.cpp b/libs/hwui/OpReorderer.cpp index 9cbd9c2d9ffc..9460361f9451 100644 --- a/libs/hwui/OpReorderer.cpp +++ b/libs/hwui/OpReorderer.cpp @@ -202,6 +202,9 @@ public: if (newClipSideFlags & OpClipSideFlags::Bottom) mClipRect.bottom = opClip.bottom; } + bool getClipSideFlags() const { return mClipSideFlags; } + const Rect& getClipRect() const { return mClipRect; } + private: int mClipSideFlags = 0; Rect mClipRect; @@ -291,12 +294,31 @@ void OpReorderer::LayerReorderer::deferMergeableOp(LinearAllocator& allocator, } } -void OpReorderer::LayerReorderer::replayBakedOpsImpl(void* arg, BakedOpDispatcher* receivers) const { +void OpReorderer::LayerReorderer::replayBakedOpsImpl(void* arg, + BakedOpReceiver* unmergedReceivers, MergedOpReceiver* mergedReceivers) const { ATRACE_NAME("flush drawing commands"); for (const BatchBase* batch : mBatches) { - // TODO: different behavior based on batch->isMerging() - for (const BakedOpState* op : batch->getOps()) { - receivers[op->op->opId](arg, *op->op, *op); + size_t size = batch->getOps().size(); + if (size > 1 && batch->isMerging()) { + int opId = batch->getOps()[0]->op->opId; + const MergingOpBatch* mergingBatch = static_cast(batch); + MergedBakedOpList data = { + batch->getOps().data(), + size, + mergingBatch->getClipSideFlags(), + mergingBatch->getClipRect() + }; + if (data.clipSideFlags) { + // if right or bottom sides aren't used to clip, init them to viewport bounds + // in the clip rect, so it can be used to scissor + if (!(data.clipSideFlags & OpClipSideFlags::Right)) data.clip.right = width; + if (!(data.clipSideFlags & OpClipSideFlags::Bottom)) data.clip.bottom = height; + } + mergedReceivers[opId](arg, data); + } else { + for (const BakedOpState* op : batch->getOps()) { + unmergedReceivers[op->op->opId](arg, *op); + } } } } @@ -639,7 +661,8 @@ void OpReorderer::deferProjectedChildren(const RenderNode& renderNode) { #define OP_RECEIVER(Type) \ [](OpReorderer& reorderer, const RecordedOp& op) { reorderer.on##Type(static_cast(op)); }, void OpReorderer::deferNodeOps(const RenderNode& renderNode) { - static std::function receivers[] = { + typedef void (*OpDispatcher) (OpReorderer& reorderer, const RecordedOp& op); + static OpDispatcher receivers[] = { MAP_OPS(OP_RECEIVER) }; @@ -692,42 +715,57 @@ static batchid_t tessellatedBatchId(const SkPaint& paint) { } void OpReorderer::onBitmapOp(const BitmapOp& op) { - BakedOpState* bakedStateOp = tryBakeOpState(op); - if (!bakedStateOp) return; // quick rejected - - mergeid_t mergeId = (mergeid_t) op.bitmap->getGenerationID(); - // TODO: AssetAtlas - currentLayer().deferMergeableOp(mAllocator, bakedStateOp, OpBatchType::Bitmap, mergeId); + BakedOpState* bakedState = tryBakeOpState(op); + if (!bakedState) return; // quick rejected + + // Don't merge non-simply transformed or neg scale ops, SET_TEXTURE doesn't handle rotation + // Don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in + // MergingDrawBatch::canMergeWith() + if (bakedState->computedState.transform.isSimple() + && bakedState->computedState.transform.positiveScale() + && PaintUtils::getXfermodeDirect(op.paint) == SkXfermode::kSrcOver_Mode + && op.bitmap->colorType() != kAlpha_8_SkColorType) { + mergeid_t mergeId = (mergeid_t) op.bitmap->getGenerationID(); + // TODO: AssetAtlas in mergeId + currentLayer().deferMergeableOp(mAllocator, bakedState, OpBatchType::Bitmap, mergeId); + } else { + currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap); + } } void OpReorderer::onLinesOp(const LinesOp& op) { - BakedOpState* bakedStateOp = tryBakeOpState(op); - if (!bakedStateOp) return; // quick rejected - currentLayer().deferUnmergeableOp(mAllocator, bakedStateOp, OpBatchType::Vertices); - + BakedOpState* bakedState = tryBakeOpState(op); + if (!bakedState) return; // quick rejected + currentLayer().deferUnmergeableOp(mAllocator, bakedState, tessellatedBatchId(*op.paint)); } void OpReorderer::onRectOp(const RectOp& op) { - BakedOpState* bakedStateOp = tryBakeOpState(op); - if (!bakedStateOp) return; // quick rejected - currentLayer().deferUnmergeableOp(mAllocator, bakedStateOp, tessellatedBatchId(*op.paint)); + BakedOpState* bakedState = tryBakeOpState(op); + if (!bakedState) return; // quick rejected + currentLayer().deferUnmergeableOp(mAllocator, bakedState, tessellatedBatchId(*op.paint)); } void OpReorderer::onSimpleRectsOp(const SimpleRectsOp& op) { - BakedOpState* bakedStateOp = tryBakeOpState(op); - if (!bakedStateOp) return; // quick rejected - currentLayer().deferUnmergeableOp(mAllocator, bakedStateOp, OpBatchType::Vertices); + BakedOpState* bakedState = tryBakeOpState(op); + if (!bakedState) return; // quick rejected + currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Vertices); } void OpReorderer::onTextOp(const TextOp& op) { - BakedOpState* bakedStateOp = tryBakeOpState(op); - if (!bakedStateOp) return; // quick rejected + BakedOpState* bakedState = tryBakeOpState(op); + if (!bakedState) return; // quick rejected // TODO: better handling of shader (since we won't care about color then) batchid_t batchId = op.paint->getColor() == SK_ColorBLACK ? OpBatchType::Text : OpBatchType::ColorText; - mergeid_t mergeId = reinterpret_cast(op.paint->getColor()); - currentLayer().deferMergeableOp(mAllocator, bakedStateOp, batchId, mergeId); + + if (bakedState->computedState.transform.isPureTranslate() + && PaintUtils::getXfermodeDirect(op.paint) == SkXfermode::kSrcOver_Mode) { + mergeid_t mergeId = reinterpret_cast(op.paint->getColor()); + currentLayer().deferMergeableOp(mAllocator, bakedState, batchId, mergeId); + } else { + currentLayer().deferUnmergeableOp(mAllocator, bakedState, batchId); + } } void OpReorderer::saveForLayer(uint32_t layerWidth, uint32_t layerHeight, diff --git a/libs/hwui/OpReorderer.h b/libs/hwui/OpReorderer.h index 00df8b0951e6..fc77c617fd89 100644 --- a/libs/hwui/OpReorderer.h +++ b/libs/hwui/OpReorderer.h @@ -58,7 +58,8 @@ namespace OpBatchType { } class OpReorderer : public CanvasStateClient { - typedef std::function BakedOpDispatcher; + typedef void (*BakedOpReceiver)(void*, const BakedOpState&); + typedef void (*MergedOpReceiver)(void*, const MergedBakedOpList& opList); /** * Stores the deferred render operations and state used to compute ordering @@ -87,7 +88,7 @@ class OpReorderer : public CanvasStateClient { void deferMergeableOp(LinearAllocator& allocator, BakedOpState* op, batchid_t batchId, mergeid_t mergeId); - void replayBakedOpsImpl(void* arg, BakedOpDispatcher* receivers) const; + void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers, MergedOpReceiver*) const; bool empty() const { return mBatches.empty(); @@ -132,19 +133,44 @@ public: * It constructs a lookup array of lambdas, which allows a recorded BakeOpState to use * state->op->opId to lookup a receiver that will be called when the op is replayed. * - * For example a BitmapOp would resolve, via the lambda lookup, to calling: - * - * StaticDispatcher::onBitmapOp(Renderer& renderer, const BitmapOp& op, const BakedOpState& state); */ -#define BAKED_OP_RECEIVER(Type) \ - [](void* internalRenderer, const RecordedOp& op, const BakedOpState& state) { \ - StaticDispatcher::on##Type(*(static_cast(internalRenderer)), static_cast(op), state); \ - }, template void replayBakedOps(Renderer& renderer) { - static BakedOpDispatcher receivers[] = { - MAP_OPS(BAKED_OP_RECEIVER) + /** + * defines a LUT of lambdas which allow a recorded BakedOpState to use state->op->opId to + * dispatch the op via a method on a static dispatcher when the op is replayed. + * + * For example a BitmapOp would resolve, via the lambda lookup, to calling: + * + * StaticDispatcher::onBitmapOp(Renderer& renderer, const BitmapOp& op, const BakedOpState& state); + */ + #define X(Type) \ + [](void* renderer, const BakedOpState& state) { \ + StaticDispatcher::on##Type(*(static_cast(renderer)), static_cast(*(state.op)), state); \ + }, + static BakedOpReceiver unmergedReceivers[] = { + MAP_OPS(X) + }; + #undef X + + /** + * defines a LUT of lambdas which allow merged arrays of BakedOpState* to be passed to a + * static dispatcher when the group of merged ops is replayed. Unmergeable ops trigger + * a LOG_ALWAYS_FATAL(). + */ + #define X(Type) \ + [](void* renderer, const MergedBakedOpList& opList) { \ + LOG_ALWAYS_FATAL("op type %d does not support merging", opList.states[0]->op->opId); \ + }, + #define Y(Type) \ + [](void* renderer, const MergedBakedOpList& opList) { \ + StaticDispatcher::onMerged##Type##s(*(static_cast(renderer)), opList); \ + }, + static MergedOpReceiver mergedReceivers[] = { + MAP_OPS_BASED_ON_MERGEABILITY(X, Y) }; + #undef X + #undef Y // Relay through layers in reverse order, since layers // later in the list will be drawn by earlier ones @@ -153,18 +179,18 @@ public: if (layer.renderNode) { // cached HW layer - can't skip layer if empty renderer.startRepaintLayer(layer.offscreenBuffer, layer.repaintRect); - layer.replayBakedOpsImpl((void*)&renderer, receivers); + layer.replayBakedOpsImpl((void*)&renderer, unmergedReceivers, mergedReceivers); renderer.endLayer(); } else if (!layer.empty()) { // save layer - skip entire layer if empty layer.offscreenBuffer = renderer.startTemporaryLayer(layer.width, layer.height); - layer.replayBakedOpsImpl((void*)&renderer, receivers); + layer.replayBakedOpsImpl((void*)&renderer, unmergedReceivers, mergedReceivers); renderer.endLayer(); } } const LayerReorderer& fbo0 = mLayerReorderers[0]; renderer.startFrame(fbo0.width, fbo0.height, fbo0.repaintRect); - fbo0.replayBakedOpsImpl((void*)&renderer, receivers); + fbo0.replayBakedOpsImpl((void*)&renderer, unmergedReceivers, mergedReceivers); renderer.endFrame(); } @@ -213,7 +239,7 @@ private: void deferRenderNodeOp(const RenderNodeOp& op); - void replayBakedOpsImpl(void* arg, BakedOpDispatcher* receivers); + void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers); SkPath* createFrameAllocatedPath() { mFrameAllocatedPaths.emplace_back(new SkPath); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index e386b1cacf74..2cb32c404525 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -1525,7 +1525,7 @@ void OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int m colors = tempColors.get(); } - Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap); + Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap->pixelRef()); const UvMapper& mapper(getMapper(texture)); for (int32_t y = 0; y < meshHeight; y++) { @@ -2146,7 +2146,7 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float bool status; #if HWUI_NEW_OPS LOG_ALWAYS_FATAL("unsupported"); - TextDrawFunctor functor(nullptr, nullptr, x, y, pureTranslate, alpha, mode, paint); + TextDrawFunctor functor(nullptr, nullptr, nullptr, x, y, pureTranslate, alpha, mode, paint); #else TextDrawFunctor functor(this, x, y, pureTranslate, alpha, mode, paint); #endif @@ -2190,7 +2190,7 @@ void OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count, SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(paint); #if HWUI_NEW_OPS LOG_ALWAYS_FATAL("unsupported"); - TextDrawFunctor functor(nullptr, nullptr, 0.0f, 0.0f, false, alpha, mode, paint); + TextDrawFunctor functor(nullptr, nullptr, nullptr, 0.0f, 0.0f, false, alpha, mode, paint); #else TextDrawFunctor functor(this, 0.0f, 0.0f, false, alpha, mode, paint); #endif @@ -2308,7 +2308,7 @@ void OpenGLRenderer::setDrawFilter(SkDrawFilter* filter) { /////////////////////////////////////////////////////////////////////////////// Texture* OpenGLRenderer::getTexture(const SkBitmap* bitmap) { - Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap); + Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap->pixelRef()); if (!texture) { return mCaches.textureCache.get(bitmap); } diff --git a/libs/hwui/PathTessellator.cpp b/libs/hwui/PathTessellator.cpp index b57b8f04d1de..9246237aeffb 100644 --- a/libs/hwui/PathTessellator.cpp +++ b/libs/hwui/PathTessellator.cpp @@ -799,7 +799,7 @@ static void instanceVertices(VertexBuffer& srcBuffer, VertexBuffer& dstBuffer, dstBuffer.alloc(numPoints * verticesPerPoint + (numPoints - 1) * 2); for (int i = 0; i < count; i += 2) { - bounds.expandToCoverVertex(points[i + 0], points[i + 1]); + bounds.expandToCover(points[i + 0], points[i + 1]); dstBuffer.copyInto(srcBuffer, points[i + 0], points[i + 1]); } dstBuffer.createDegenerateSeparators(verticesPerPoint); @@ -878,8 +878,8 @@ void PathTessellator::tessellateLines(const float* points, int count, const SkPa } // calculate bounds - bounds.expandToCoverVertex(tempVerticesData[0].x, tempVerticesData[0].y); - bounds.expandToCoverVertex(tempVerticesData[1].x, tempVerticesData[1].y); + bounds.expandToCover(tempVerticesData[0].x, tempVerticesData[0].y); + bounds.expandToCover(tempVerticesData[1].x, tempVerticesData[1].y); } // since multiple objects tessellated into buffer, separate them with degen tris diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h index b4a201ed2374..b96640144657 100644 --- a/libs/hwui/RecordedOp.h +++ b/libs/hwui/RecordedOp.h @@ -37,21 +37,34 @@ class RenderNode; struct Vertex; /** - * The provided macro is executed for each op type in order, with the results separated by commas. + * On of the provided macros is executed for each op type in order. The first will be used for ops + * that cannot merge, and the second for those that can. * * This serves as the authoritative list of ops, used for generating ID enum, and ID based LUTs. */ +#define MAP_OPS_BASED_ON_MERGEABILITY(U_OP_FN, M_OP_FN) \ + M_OP_FN(BitmapOp) \ + U_OP_FN(LinesOp) \ + U_OP_FN(RectOp) \ + U_OP_FN(RenderNodeOp) \ + U_OP_FN(ShadowOp) \ + U_OP_FN(SimpleRectsOp) \ + M_OP_FN(TextOp) \ + U_OP_FN(BeginLayerOp) \ + U_OP_FN(EndLayerOp) \ + U_OP_FN(LayerOp) + +/** + * The provided macro is executed for each op type in order. This is used in cases where + * merge-ability of ops doesn't matter. + */ #define MAP_OPS(OP_FN) \ - OP_FN(BitmapOp) \ - OP_FN(LinesOp) \ - OP_FN(RectOp) \ - OP_FN(RenderNodeOp) \ - OP_FN(ShadowOp) \ - OP_FN(SimpleRectsOp) \ - OP_FN(TextOp) \ - OP_FN(BeginLayerOp) \ - OP_FN(EndLayerOp) \ - OP_FN(LayerOp) + MAP_OPS_BASED_ON_MERGEABILITY(OP_FN, OP_FN) + +#define NULL_OP_FN(Type) + +#define MAP_MERGED_OPS(OP_FN) \ + MAP_OPS_BASED_ON_MERGEABILITY(NULL_OP_FN, OP_FN) // Generate OpId enum #define IDENTITY_FN(Type) Type, diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp index 69c686ec3ba2..e6020cdba266 100644 --- a/libs/hwui/RecordingCanvas.cpp +++ b/libs/hwui/RecordingCanvas.cpp @@ -248,10 +248,7 @@ void RecordingCanvas::drawLines(const float* points, int floatCount, const SkPai Rect unmappedBounds(points[0], points[1], points[0], points[1]); for (int i = 2; i < floatCount; i += 2) { - unmappedBounds.left = std::min(unmappedBounds.left, points[i]); - unmappedBounds.right = std::max(unmappedBounds.right, points[i]); - unmappedBounds.top = std::min(unmappedBounds.top, points[i + 1]); - unmappedBounds.bottom = std::max(unmappedBounds.bottom, points[i + 1]); + unmappedBounds.expandToCover(points[i], points[i + 1]); } // since anything AA stroke with less than 1.0 pixel width is drawn with an alpha-reduced @@ -413,6 +410,7 @@ void RecordingCanvas::drawText(const uint16_t* glyphs, const float* positions, i glyphs = refBuffer(glyphs, glyphCount); positions = refBuffer(positions, glyphCount * 2); + // TODO: either must account for text shadow in bounds, or record separate ops for text shadows addOp(new (alloc()) TextOp( Rect(boundsLeft, boundsTop, boundsRight, boundsBottom), *(mState.currentSnapshot()->transform), diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h index 472aad711432..30c925c8775b 100644 --- a/libs/hwui/Rect.h +++ b/libs/hwui/Rect.h @@ -253,7 +253,18 @@ public: bottom = ceilf(bottom); } - void expandToCoverVertex(float x, float y) { + /* + * Similar to unionWith, except this makes the assumption that both rects are non-empty + * to avoid both emptiness checks. + */ + void expandToCover(const Rect& other) { + left = std::min(left, other.left); + top = std::min(top, other.top); + right = std::max(right, other.right); + bottom = std::max(bottom, other.bottom); + } + + void expandToCover(float x, float y) { left = std::min(left, x); top = std::min(top, y); right = std::max(right, x); diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp index a6c72a380805..21901cf4414b 100644 --- a/libs/hwui/TextureCache.cpp +++ b/libs/hwui/TextureCache.cpp @@ -138,7 +138,7 @@ bool TextureCache::canMakeTextureFromBitmap(const SkBitmap* bitmap) { // in the cache (and is thus added to the cache) Texture* TextureCache::getCachedTexture(const SkBitmap* bitmap, AtlasUsageType atlasUsageType) { if (CC_LIKELY(mAssetAtlas != nullptr) && atlasUsageType == AtlasUsageType::Use) { - AssetAtlas::Entry* entry = mAssetAtlas->getEntry(bitmap); + AssetAtlas::Entry* entry = mAssetAtlas->getEntry(bitmap->pixelRef()); if (CC_UNLIKELY(entry)) { return entry->texture; } diff --git a/libs/hwui/VertexBuffer.h b/libs/hwui/VertexBuffer.h index c0373aceebba..bdb5b7b381bf 100644 --- a/libs/hwui/VertexBuffer.h +++ b/libs/hwui/VertexBuffer.h @@ -118,7 +118,7 @@ public: TYPE* end = current + vertexCount; mBounds.set(current->x, current->y, current->x, current->y); for (; current < end; current++) { - mBounds.expandToCoverVertex(current->x, current->y); + mBounds.expandToCover(current->x, current->y); } } diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h index 9c1c0b9d2c08..0af99398b5f5 100644 --- a/libs/hwui/tests/common/TestUtils.h +++ b/libs/hwui/tests/common/TestUtils.h @@ -103,10 +103,11 @@ public: return snapshot; } - static SkBitmap createSkBitmap(int width, int height) { + static SkBitmap createSkBitmap(int width, int height, + SkColorType colorType = kN32_SkColorType) { SkBitmap bitmap; SkImageInfo info = SkImageInfo::Make(width, height, - kN32_SkColorType, kPremul_SkAlphaType); + colorType, kPremul_SkAlphaType); bitmap.setInfo(info); bitmap.allocPixels(info); return bitmap; diff --git a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp index 27adb125fcf9..6c64a327013e 100644 --- a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp +++ b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp @@ -62,7 +62,9 @@ public: int cardIndexOffset = scrollPx / (cardSpacing + cardHeight); int pxOffset = -(scrollPx % (cardSpacing + cardHeight)); - TestCanvas canvas(cardWidth, cardHeight); + TestCanvas canvas( + listView->stagingProperties().getWidth(), + listView->stagingProperties().getHeight()); for (size_t ci = 0; ci < cards.size(); ci++) { // update card position auto card = cards[(ci + cardIndexOffset) % cards.size()]; @@ -121,9 +123,11 @@ private: static SkBitmap filledBox = createBoxBitmap(true); static SkBitmap strokedBox = createBoxBitmap(false); - props.mutableOutline().setRoundRect(0, 0, cardWidth, cardHeight, dp(6), 1); - props.mutableOutline().setShouldClip(true); - canvas.drawColor(Color::White, SkXfermode::kSrcOver_Mode); + // TODO: switch to using round rect clipping, once merging correctly handles that + SkPaint roundRectPaint; + roundRectPaint.setAntiAlias(true); + roundRectPaint.setColor(Color::White); + canvas.drawRoundRect(0, 0, cardWidth, cardHeight, dp(6), dp(6), roundRectPaint); SkPaint textPaint; textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); diff --git a/libs/hwui/tests/microbench/OpReordererBench.cpp b/libs/hwui/tests/microbench/OpReordererBench.cpp index 406bfcc684b1..ac2b15cc620a 100644 --- a/libs/hwui/tests/microbench/OpReordererBench.cpp +++ b/libs/hwui/tests/microbench/OpReordererBench.cpp @@ -25,7 +25,7 @@ #include "RecordingCanvas.h" #include "tests/common/TestUtils.h" #include "Vector.h" -#include "microbench/MicroBench.h" +#include "tests/microbench/MicroBench.h" #include diff --git a/libs/hwui/tests/unit/OpReordererTests.cpp b/libs/hwui/tests/unit/OpReordererTests.cpp index 98a430a0ef10..068e832bac5c 100644 --- a/libs/hwui/tests/unit/OpReordererTests.cpp +++ b/libs/hwui/tests/unit/OpReordererTests.cpp @@ -65,12 +65,22 @@ public: virtual void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) {} virtual void endFrame() {} - // define virtual defaults for direct -#define BASE_OP_METHOD(Type) \ + // define virtual defaults for single draw methods +#define X(Type) \ virtual void on##Type(const Type&, const BakedOpState&) { \ ADD_FAILURE() << #Type " not expected in this test"; \ } - MAP_OPS(BASE_OP_METHOD) + MAP_OPS(X) +#undef X + + // define virtual defaults for merged draw methods +#define X(Type) \ + virtual void onMerged##Type##s(const MergedBakedOpList& opList) { \ + ADD_FAILURE() << "Merged " #Type "s not expected in this test"; \ + } + MAP_MERGED_OPS(X) +#undef X + int getIndex() { return mIndex; } protected: @@ -83,11 +93,21 @@ protected: */ class TestDispatcher { public: -#define DISPATCHER_METHOD(Type) \ + // define single op methods, which redirect to TestRendererBase +#define X(Type) \ static void on##Type(TestRendererBase& renderer, const Type& op, const BakedOpState& state) { \ renderer.on##Type(op, state); \ } - MAP_OPS(DISPATCHER_METHOD); + MAP_OPS(X); +#undef X + + // define merged op methods, which redirect to TestRendererBase +#define X(Type) \ + static void onMerged##Type##s(TestRendererBase& renderer, const MergedBakedOpList& opList) { \ + renderer.onMerged##Type##s(opList); \ + } + MAP_MERGED_OPS(X); +#undef X }; class FailRenderer : public TestRendererBase {}; @@ -153,7 +173,8 @@ TEST(OpReorderer, simpleBatching) { auto node = TestUtils::createNode(0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) { - SkBitmap bitmap = TestUtils::createSkBitmap(10, 10); + SkBitmap bitmap = TestUtils::createSkBitmap(10, 10, + kAlpha_8_SkColorType); // Disable merging by using alpha 8 bitmap // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects. // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group. @@ -171,7 +192,7 @@ TEST(OpReorderer, simpleBatching) { SimpleBatchingTestRenderer renderer; reorderer.replayBakedOps(renderer); EXPECT_EQ(2 * LOOPS, renderer.getIndex()) - << "Expect number of ops = 2 * loop count"; // TODO: force no merging + << "Expect number of ops = 2 * loop count"; } TEST(OpReorderer, textStrikethroughBatching) { @@ -181,8 +202,10 @@ TEST(OpReorderer, textStrikethroughBatching) { void onRectOp(const RectOp& op, const BakedOpState& state) override { EXPECT_TRUE(mIndex++ >= LOOPS) << "Strikethrough rects should be above all text"; } - void onTextOp(const TextOp& op, const BakedOpState& state) override { - EXPECT_TRUE(mIndex++ < LOOPS) << "Text should be beneath all strikethrough rects"; + void onMergedTextOps(const MergedBakedOpList& opList) override { + EXPECT_EQ(0, mIndex); + mIndex += opList.count; + EXPECT_EQ(5u, opList.count); } }; auto node = TestUtils::createNode(0, 0, 200, 2000, -- cgit v1.2.3-59-g8ed1b From 38e0c32852e3b9d8ca4a9d3791577f52536419cb Mon Sep 17 00:00:00 2001 From: John Reck Date: Tue, 10 Nov 2015 12:19:17 -0800 Subject: Track texture memory globally Also mostly consolidates texture creation Change-Id: Ifea01303afda531dcec99b8fe2a0f64cf2f24420 --- libs/hwui/Android.mk | 2 + libs/hwui/AssetAtlas.cpp | 57 +++--- libs/hwui/AssetAtlas.h | 31 ++-- libs/hwui/BakedOpDispatcher.cpp | 14 +- libs/hwui/BakedOpRenderer.cpp | 6 +- libs/hwui/GpuMemoryTracker.cpp | 140 +++++++++++++++ libs/hwui/GpuMemoryTracker.h | 76 ++++++++ libs/hwui/GradientCache.cpp | 24 +-- libs/hwui/GradientCache.h | 3 +- libs/hwui/Layer.cpp | 35 ++-- libs/hwui/Layer.h | 17 +- libs/hwui/LayerCache.cpp | 1 - libs/hwui/OpenGLRenderer.cpp | 18 +- libs/hwui/PathCache.cpp | 33 +--- libs/hwui/PathCache.h | 4 +- libs/hwui/SkiaShader.cpp | 6 +- libs/hwui/TextDropShadowCache.cpp | 9 +- libs/hwui/Texture.cpp | 208 +++++++++++++++++++++- libs/hwui/Texture.h | 85 +++++++-- libs/hwui/TextureCache.cpp | 9 +- libs/hwui/TextureCache.h | 1 + libs/hwui/font/CacheTexture.cpp | 28 +-- libs/hwui/font/CacheTexture.h | 7 +- libs/hwui/renderstate/OffscreenBufferPool.cpp | 31 ++-- libs/hwui/renderstate/OffscreenBufferPool.h | 10 +- libs/hwui/renderstate/RenderState.cpp | 8 +- libs/hwui/renderstate/TextureState.cpp | 128 ------------- libs/hwui/renderstate/TextureState.h | 7 - libs/hwui/renderthread/CanvasContext.cpp | 3 + libs/hwui/tests/common/TestUtils.h | 4 + libs/hwui/tests/macrobench/main.cpp | 1 + libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp | 70 ++++++++ libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp | 12 +- libs/hwui/tests/unit/StringUtilsTests.cpp | 15 ++ libs/hwui/utils/StringUtils.h | 17 ++ 35 files changed, 743 insertions(+), 377 deletions(-) create mode 100644 libs/hwui/GpuMemoryTracker.cpp create mode 100644 libs/hwui/GpuMemoryTracker.h create mode 100644 libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp (limited to 'libs/hwui/TextureCache.cpp') diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index bbfc0221666c..cdd891fa5644 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -53,6 +53,7 @@ hwui_src_files := \ FrameInfoVisualizer.cpp \ GammaFontRenderer.cpp \ GlopBuilder.cpp \ + GpuMemoryTracker.cpp \ GradientCache.cpp \ Image.cpp \ Interpolator.cpp \ @@ -228,6 +229,7 @@ LOCAL_SRC_FILES += \ tests/unit/DamageAccumulatorTests.cpp \ tests/unit/DeviceInfoTests.cpp \ tests/unit/FatVectorTests.cpp \ + tests/unit/GpuMemoryTrackerTests.cpp \ tests/unit/LayerUpdateQueueTests.cpp \ tests/unit/LinearAllocatorTests.cpp \ tests/unit/VectorDrawableTests.cpp \ diff --git a/libs/hwui/AssetAtlas.cpp b/libs/hwui/AssetAtlas.cpp index 41411a98a4bf..6afff1b7158e 100644 --- a/libs/hwui/AssetAtlas.cpp +++ b/libs/hwui/AssetAtlas.cpp @@ -39,40 +39,22 @@ void AssetAtlas::init(sp buffer, int64_t* map, int count) { if (!mTexture) { Caches& caches = Caches::getInstance(); mTexture = new Texture(caches); - mTexture->width = buffer->getWidth(); - mTexture->height = buffer->getHeight(); + mTexture->wrap(mImage->getTexture(), + buffer->getWidth(), buffer->getHeight(), GL_RGBA); createEntries(caches, map, count); } } else { ALOGW("Could not create atlas image"); - delete mImage; - mImage = nullptr; + terminate(); } - - updateTextureId(); } void AssetAtlas::terminate() { - if (mImage) { - delete mImage; - mImage = nullptr; - updateTextureId(); - } -} - - -void AssetAtlas::updateTextureId() { - mTexture->id = mImage ? mImage->getTexture() : 0; - if (mTexture->id) { - // Texture ID changed, force-set to defaults to sync the wrapper & GL - // state objects - mTexture->setWrap(GL_CLAMP_TO_EDGE, false, true); - mTexture->setFilter(GL_NEAREST, false, true); - } - for (size_t i = 0; i < mEntries.size(); i++) { - AssetAtlas::Entry* entry = mEntries.valueAt(i); - entry->texture->id = mTexture->id; - } + delete mImage; + mImage = nullptr; + delete mTexture; + mTexture = nullptr; + mEntries.clear(); } /////////////////////////////////////////////////////////////////////////////// @@ -80,13 +62,13 @@ void AssetAtlas::updateTextureId() { /////////////////////////////////////////////////////////////////////////////// AssetAtlas::Entry* AssetAtlas::getEntry(const SkPixelRef* pixelRef) const { - ssize_t index = mEntries.indexOfKey(pixelRef); - return index >= 0 ? mEntries.valueAt(index) : nullptr; + auto result = mEntries.find(pixelRef); + return result != mEntries.end() ? result->second.get() : nullptr; } Texture* AssetAtlas::getEntryTexture(const SkPixelRef* pixelRef) const { - ssize_t index = mEntries.indexOfKey(pixelRef); - return index >= 0 ? mEntries.valueAt(index)->texture : nullptr; + auto result = mEntries.find(pixelRef); + return result != mEntries.end() ? result->second->texture : nullptr; } /** @@ -94,7 +76,8 @@ Texture* AssetAtlas::getEntryTexture(const SkPixelRef* pixelRef) const { * instead of applying the changes to the virtual textures. */ struct DelegateTexture: public Texture { - DelegateTexture(Caches& caches, Texture* delegate): Texture(caches), mDelegate(delegate) { } + DelegateTexture(Caches& caches, Texture* delegate) + : Texture(caches), mDelegate(delegate) { } virtual void setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture = false, bool force = false, GLenum renderTarget = GL_TEXTURE_2D) override { @@ -111,8 +94,8 @@ private: }; // struct DelegateTexture void AssetAtlas::createEntries(Caches& caches, int64_t* map, int count) { - const float width = float(mTexture->width); - const float height = float(mTexture->height); + const float width = float(mTexture->width()); + const float height = float(mTexture->height()); for (int i = 0; i < count; ) { SkPixelRef* pixelRef = reinterpret_cast(map[i++]); @@ -133,13 +116,13 @@ void AssetAtlas::createEntries(Caches& caches, int64_t* map, int count) { Texture* texture = new DelegateTexture(caches, mTexture); texture->blend = !SkAlphaTypeIsOpaque(pixelRef->info().alphaType()); - texture->width = pixelRef->info().width(); - texture->height = pixelRef->info().height(); + texture->wrap(mTexture->id(), pixelRef->info().width(), + pixelRef->info().height(), mTexture->format()); - Entry* entry = new Entry(pixelRef, texture, mapper, *this); + std::unique_ptr entry(new Entry(pixelRef, texture, mapper, *this)); texture->uvMapper = &entry->uvMapper; - mEntries.add(entry->pixelRef, entry); + mEntries.emplace(entry->pixelRef, std::move(entry)); } } diff --git a/libs/hwui/AssetAtlas.h b/libs/hwui/AssetAtlas.h index a037725b1c6c..75400ff494c3 100644 --- a/libs/hwui/AssetAtlas.h +++ b/libs/hwui/AssetAtlas.h @@ -17,18 +17,16 @@ #ifndef ANDROID_HWUI_ASSET_ATLAS_H #define ANDROID_HWUI_ASSET_ATLAS_H -#include - -#include - -#include +#include "Texture.h" +#include "UvMapper.h" #include - +#include +#include #include -#include "Texture.h" -#include "UvMapper.h" +#include +#include namespace android { namespace uirenderer { @@ -71,6 +69,10 @@ public: return texture->blend ? &atlas.mBlendKey : &atlas.mOpaqueKey; } + ~Entry() { + delete texture; + } + private: /** * The pixel ref that generated this atlas entry. @@ -90,10 +92,6 @@ public: , atlas(atlas) { } - ~Entry() { - delete texture; - } - friend class AssetAtlas; }; @@ -127,7 +125,7 @@ public: * Can return 0 if the atlas is not initialized. */ uint32_t getWidth() const { - return mTexture ? mTexture->width : 0; + return mTexture ? mTexture->width() : 0; } /** @@ -135,7 +133,7 @@ public: * Can return 0 if the atlas is not initialized. */ uint32_t getHeight() const { - return mTexture ? mTexture->height : 0; + return mTexture ? mTexture->height() : 0; } /** @@ -143,7 +141,7 @@ public: * Can return 0 if the atlas is not initialized. */ GLuint getTexture() const { - return mTexture ? mTexture->id : 0; + return mTexture ? mTexture->id() : 0; } /** @@ -160,7 +158,6 @@ public: private: void createEntries(Caches& caches, int64_t* map, int count); - void updateTextureId(); Texture* mTexture; Image* mImage; @@ -168,7 +165,7 @@ private: const bool mBlendKey; const bool mOpaqueKey; - KeyedVector mEntries; + std::unordered_map> mEntries; }; // class AssetAtlas }; // namespace uirenderer diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp index 5b34f6b79199..6b0c1499336f 100644 --- a/libs/hwui/BakedOpDispatcher.cpp +++ b/libs/hwui/BakedOpDispatcher.cpp @@ -217,7 +217,7 @@ static void renderTextShadow(BakedOpRenderer& renderer, FontRenderer& fontRender .setMeshTexturedUnitQuad(nullptr) .setFillShadowTexturePaint(*texture, textShadow.color, *op.paint, state.alpha) .setTransform(state.computedState.transform, TransformFlags::None) - .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width, sy + texture->height)) + .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width(), sy + texture->height())) .build(); renderer.renderGlop(state, glop); } @@ -337,7 +337,7 @@ static void renderConvexPath(BakedOpRenderer& renderer, const BakedOpState& stat static void renderPathTexture(BakedOpRenderer& renderer, const BakedOpState& state, PathTexture& texture, const RecordedOp& op) { - Rect dest(texture.width, texture.height); + Rect dest(texture.width(), texture.height()); dest.translate(texture.left - texture.offset, texture.top - texture.offset); Glop glop; @@ -399,7 +399,7 @@ void BakedOpDispatcher::onBitmapOp(BakedOpRenderer& renderer, const BitmapOp& op .setMeshTexturedUnitQuad(texture->uvMapper) .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha) .setTransform(state.computedState.transform, TransformFlags::None) - .setModelViewMapUnitToRectSnap(Rect(texture->width, texture->height)) + .setModelViewMapUnitToRectSnap(Rect(texture->width(), texture->height())) .build(); renderer.renderGlop(state, glop); } @@ -483,10 +483,10 @@ void BakedOpDispatcher::onBitmapRectOp(BakedOpRenderer& renderer, const BitmapRe if (!texture) return; const AutoTexture autoCleanup(texture); - Rect uv(std::max(0.0f, op.src.left / texture->width), - std::max(0.0f, op.src.top / texture->height), - std::min(1.0f, op.src.right / texture->width), - std::min(1.0f, op.src.bottom / texture->height)); + Rect uv(std::max(0.0f, op.src.left / texture->width()), + std::max(0.0f, op.src.top / texture->height()), + std::min(1.0f, op.src.right / texture->width()), + std::min(1.0f, op.src.bottom / texture->height())); const int textureFillFlags = (op.bitmap->colorType() == kAlpha_8_SkColorType) ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None; diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp index 42fb66fe9845..4fbff0d107ba 100644 --- a/libs/hwui/BakedOpRenderer.cpp +++ b/libs/hwui/BakedOpRenderer.cpp @@ -48,7 +48,7 @@ void BakedOpRenderer::startRepaintLayer(OffscreenBuffer* offscreenBuffer, const // attach the texture to the FBO glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - offscreenBuffer->texture.id, 0); + offscreenBuffer->texture.id(), 0); LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "startLayer FAILED"); LOG_ALWAYS_FATAL_IF(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE, "framebuffer incomplete!"); @@ -84,7 +84,7 @@ OffscreenBuffer* BakedOpRenderer::copyToLayer(const Rect& area) { area.getWidth(), area.getHeight()); if (!area.isEmpty()) { mCaches.textureState().activateTexture(0); - mCaches.textureState().bindTexture(buffer->texture.id); + mCaches.textureState().bindTexture(buffer->texture.id()); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, area.left, mRenderTarget.viewportHeight - area.bottom, @@ -272,7 +272,7 @@ void BakedOpRenderer::prepareRender(const Rect* dirtyBounds, const ClipBase* cli OffscreenBuffer* layer = mRenderTarget.offscreenBuffer; mRenderTarget.stencil = mCaches.renderBufferCache.get( Stencil::getLayerStencilFormat(), - layer->texture.width, layer->texture.height); + layer->texture.width(), layer->texture.height()); // stencil is bound + allocated - associate it with current FBO glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, mRenderTarget.stencil->getName()); diff --git a/libs/hwui/GpuMemoryTracker.cpp b/libs/hwui/GpuMemoryTracker.cpp new file mode 100644 index 000000000000..4fb57019264d --- /dev/null +++ b/libs/hwui/GpuMemoryTracker.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "utils/StringUtils.h" +#include "Texture.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace android { +namespace uirenderer { + +pthread_t gGpuThread = 0; + +#define NUM_TYPES static_cast(GpuObjectType::TypeCount) + +const char* TYPE_NAMES[] = { + "Texture", + "OffscreenBuffer", + "Layer", +}; + +struct TypeStats { + int totalSize = 0; + int count = 0; +}; + +static std::array gObjectStats; +static std::unordered_set gObjectSet; + +void GpuMemoryTracker::notifySizeChanged(int newSize) { + int delta = newSize - mSize; + mSize = newSize; + gObjectStats[static_cast(mType)].totalSize += delta; +} + +void GpuMemoryTracker::startTrackingObject() { + auto result = gObjectSet.insert(this); + LOG_ALWAYS_FATAL_IF(!result.second, + "startTrackingObject() on %p failed, already being tracked!", this); + gObjectStats[static_cast(mType)].count++; +} + +void GpuMemoryTracker::stopTrackingObject() { + size_t removed = gObjectSet.erase(this); + LOG_ALWAYS_FATAL_IF(removed != 1, + "stopTrackingObject removed %zd, is %p not being tracked?", + removed, this); + gObjectStats[static_cast(mType)].count--; +} + +void GpuMemoryTracker::onGLContextCreated() { + LOG_ALWAYS_FATAL_IF(gGpuThread != 0, "We already have a GL thread? " + "current = %lu, gl thread = %lu", pthread_self(), gGpuThread); + gGpuThread = pthread_self(); +} + +void GpuMemoryTracker::onGLContextDestroyed() { + gGpuThread = 0; + if (CC_UNLIKELY(gObjectSet.size() > 0)) { + std::stringstream os; + dump(os); + ALOGE("%s", os.str().c_str()); + LOG_ALWAYS_FATAL("Leaked %zd GPU objects!", gObjectSet.size()); + } +} + +void GpuMemoryTracker::dump() { + std::stringstream strout; + dump(strout); + ALOGD("%s", strout.str().c_str()); +} + +void GpuMemoryTracker::dump(std::ostream& stream) { + for (int type = 0; type < NUM_TYPES; type++) { + const TypeStats& stats = gObjectStats[type]; + stream << TYPE_NAMES[type]; + stream << " is using " << SizePrinter{stats.totalSize}; + stream << ", count = " << stats.count; + stream << std::endl; + } +} + +int GpuMemoryTracker::getInstanceCount(GpuObjectType type) { + return gObjectStats[static_cast(type)].count; +} + +int GpuMemoryTracker::getTotalSize(GpuObjectType type) { + return gObjectStats[static_cast(type)].totalSize; +} + +void GpuMemoryTracker::onFrameCompleted() { + if (ATRACE_ENABLED()) { + char buf[128]; + for (int type = 0; type < NUM_TYPES; type++) { + snprintf(buf, 128, "hwui_%s", TYPE_NAMES[type]); + const TypeStats& stats = gObjectStats[type]; + ATRACE_INT(buf, stats.totalSize); + snprintf(buf, 128, "hwui_%s_count", TYPE_NAMES[type]); + ATRACE_INT(buf, stats.count); + } + } + + std::vector freeList; + for (const auto& obj : gObjectSet) { + if (obj->objectType() == GpuObjectType::Texture) { + const Texture* texture = static_cast(obj); + if (texture->cleanup) { + ALOGE("Leaked texture marked for cleanup! id=%u, size %ux%u", + texture->id(), texture->width(), texture->height()); + freeList.push_back(texture); + } + } + } + for (auto& texture : freeList) { + const_cast(texture)->deleteTexture(); + delete texture; + } +} + +} // namespace uirenderer +} // namespace android; diff --git a/libs/hwui/GpuMemoryTracker.h b/libs/hwui/GpuMemoryTracker.h new file mode 100644 index 000000000000..851aeae8352c --- /dev/null +++ b/libs/hwui/GpuMemoryTracker.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include +#include +#include + +namespace android { +namespace uirenderer { + +extern pthread_t gGpuThread; + +#define ASSERT_GPU_THREAD() LOG_ALWAYS_FATAL_IF( \ + !pthread_equal(gGpuThread, pthread_self()), \ + "Error, %p of type %d (size=%d) used on wrong thread! cur thread %lu " \ + "!= gpu thread %lu", this, static_cast(mType), mSize, \ + pthread_self(), gGpuThread) + +enum class GpuObjectType { + Texture = 0, + OffscreenBuffer, + Layer, + + TypeCount, +}; + +class GpuMemoryTracker { +public: + GpuObjectType objectType() { return mType; } + int objectSize() { return mSize; } + + static void onGLContextCreated(); + static void onGLContextDestroyed(); + static void dump(); + static void dump(std::ostream& stream); + static int getInstanceCount(GpuObjectType type); + static int getTotalSize(GpuObjectType type); + static void onFrameCompleted(); + +protected: + GpuMemoryTracker(GpuObjectType type) : mType(type) { + ASSERT_GPU_THREAD(); + startTrackingObject(); + } + + ~GpuMemoryTracker() { + notifySizeChanged(0); + stopTrackingObject(); + } + + void notifySizeChanged(int newSize); + +private: + void startTrackingObject(); + void stopTrackingObject(); + + int mSize = 0; + GpuObjectType mType; +}; + +} // namespace uirenderer +} // namespace android; diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp index 8c4645092c97..522aa96132dd 100644 --- a/libs/hwui/GradientCache.cpp +++ b/libs/hwui/GradientCache.cpp @@ -110,9 +110,7 @@ void GradientCache::setMaxSize(uint32_t maxSize) { void GradientCache::operator()(GradientCacheEntry&, Texture*& texture) { if (texture) { - const uint32_t size = texture->width * texture->height * bytesPerPixel(); - mSize -= size; - + mSize -= texture->objectSize(); texture->deleteTexture(); delete texture; } @@ -167,18 +165,16 @@ Texture* GradientCache::addLinearGradient(GradientCacheEntry& gradient, getGradientInfo(colors, count, info); Texture* texture = new Texture(Caches::getInstance()); - texture->width = info.width; - texture->height = 2; texture->blend = info.hasAlpha; texture->generation = 1; // Asume the cache is always big enough - const uint32_t size = texture->width * texture->height * bytesPerPixel(); + const uint32_t size = info.width * 2 * bytesPerPixel(); while (getSize() + size > mMaxSize) { mCache.removeOldest(); } - generateTexture(colors, positions, texture); + generateTexture(colors, positions, info.width, 2, texture); mSize += size; mCache.put(gradient, texture); @@ -231,10 +227,10 @@ void GradientCache::mixFloats(GradientColor& start, GradientColor& end, float am dst += 4 * sizeof(float); } -void GradientCache::generateTexture(uint32_t* colors, float* positions, Texture* texture) { - const uint32_t width = texture->width; +void GradientCache::generateTexture(uint32_t* colors, float* positions, + const uint32_t width, const uint32_t height, Texture* texture) { const GLsizei rowBytes = width * bytesPerPixel(); - uint8_t pixels[rowBytes * texture->height]; + uint8_t pixels[rowBytes * height]; static ChannelSplitter gSplitters[] = { &android::uirenderer::GradientCache::splitToBytes, @@ -277,17 +273,13 @@ void GradientCache::generateTexture(uint32_t* colors, float* positions, Texture* memcpy(pixels + rowBytes, pixels, rowBytes); - glGenTextures(1, &texture->id); - Caches::getInstance().textureState().bindTexture(texture->id); glPixelStorei(GL_UNPACK_ALIGNMENT, 4); if (mUseFloatTexture) { // We have to use GL_RGBA16F because GL_RGBA32F does not support filtering - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, texture->height, 0, - GL_RGBA, GL_FLOAT, pixels); + texture->upload(width, height, GL_RGBA16F, GL_RGBA, GL_FLOAT, pixels); } else { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, texture->height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, pixels); + texture->upload(width, height, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, pixels); } texture->setFilter(GL_LINEAR); diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h index 7534c5d11164..b762ca7d5e5c 100644 --- a/libs/hwui/GradientCache.h +++ b/libs/hwui/GradientCache.h @@ -143,7 +143,8 @@ private: Texture* addLinearGradient(GradientCacheEntry& gradient, uint32_t* colors, float* positions, int count); - void generateTexture(uint32_t* colors, float* positions, Texture* texture); + void generateTexture(uint32_t* colors, float* positions, + const uint32_t width, const uint32_t height, Texture* texture); struct GradientInfo { uint32_t width; diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp index 0fe20ad1b662..7a74b9825d80 100644 --- a/libs/hwui/Layer.cpp +++ b/libs/hwui/Layer.cpp @@ -36,7 +36,8 @@ namespace android { namespace uirenderer { Layer::Layer(Type layerType, RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight) - : state(State::Uncached) + : GpuMemoryTracker(GpuObjectType::Layer) + , state(State::Uncached) , caches(Caches::getInstance()) , renderState(renderState) , texture(caches) @@ -45,8 +46,8 @@ Layer::Layer(Type layerType, RenderState& renderState, uint32_t layerWidth, uint // preserves the old inc/dec ref locations. This should be changed... incStrong(nullptr); renderTarget = GL_TEXTURE_2D; - texture.width = layerWidth; - texture.height = layerHeight; + texture.mWidth = layerWidth; + texture.mHeight = layerHeight; renderState.registerLayer(this); } @@ -54,10 +55,10 @@ Layer::~Layer() { renderState.unregisterLayer(this); SkSafeUnref(colorFilter); - if (stencil || fbo || texture.id) { + if (stencil || fbo || texture.mId) { renderState.requireGLContext(); removeFbo(); - deleteTexture(); + texture.deleteTexture(); } delete[] mesh; @@ -65,7 +66,7 @@ Layer::~Layer() { void Layer::onGlContextLost() { removeFbo(); - deleteTexture(); + texture.deleteTexture(); } uint32_t Layer::computeIdealWidth(uint32_t layerWidth) { @@ -179,8 +180,8 @@ void Layer::setColorFilter(SkColorFilter* filter) { } void Layer::bindTexture() const { - if (texture.id) { - caches.textureState().bindTexture(renderTarget, texture.id); + if (texture.mId) { + caches.textureState().bindTexture(renderTarget, texture.mId); } } @@ -191,28 +192,22 @@ void Layer::bindStencilRenderBuffer() const { } void Layer::generateTexture() { - if (!texture.id) { - glGenTextures(1, &texture.id); - } -} - -void Layer::deleteTexture() { - if (texture.id) { - texture.deleteTexture(); - texture.id = 0; + if (!texture.mId) { + glGenTextures(1, &texture.mId); } } void Layer::clearTexture() { - caches.textureState().unbindTexture(texture.id); - texture.id = 0; + caches.textureState().unbindTexture(texture.mId); + texture.mId = 0; } void Layer::allocateTexture() { #if DEBUG_LAYERS ALOGD(" Allocate layer: %dx%d", getWidth(), getHeight()); #endif - if (texture.id) { + if (texture.mId) { + texture.updateSize(getWidth(), getHeight(), GL_RGBA); glPixelStorei(GL_UNPACK_ALIGNMENT, 4); glTexImage2D(renderTarget, 0, GL_RGBA, getWidth(), getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index e90f055b667b..e00ae66997a5 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -24,6 +24,7 @@ #include #include +#include #include @@ -54,7 +55,7 @@ struct DeferStateStruct; /** * A layer has dimensions and is backed by an OpenGL texture or FBO. */ -class Layer : public VirtualLightRefBase { +class Layer : public VirtualLightRefBase, GpuMemoryTracker { public: enum class Type { Texture, @@ -94,8 +95,8 @@ public: regionRect.set(bounds.leftTop().x, bounds.leftTop().y, bounds.rightBottom().x, bounds.rightBottom().y); - const float texX = 1.0f / float(texture.width); - const float texY = 1.0f / float(texture.height); + const float texX = 1.0f / float(texture.mWidth); + const float texY = 1.0f / float(texture.mHeight); const float height = layer.getHeight(); texCoords.set( regionRect.left * texX, (height - regionRect.top) * texY, @@ -112,11 +113,11 @@ public: void updateDeferred(RenderNode* renderNode, int left, int top, int right, int bottom); inline uint32_t getWidth() const { - return texture.width; + return texture.mWidth; } inline uint32_t getHeight() const { - return texture.height; + return texture.mHeight; } /** @@ -131,8 +132,7 @@ public: bool resize(const uint32_t width, const uint32_t height); void setSize(uint32_t width, uint32_t height) { - texture.width = width; - texture.height = height; + texture.updateSize(width, height, texture.format()); } ANDROID_API void setPaint(const SkPaint* paint); @@ -201,7 +201,7 @@ public: } inline GLuint getTextureId() const { - return texture.id; + return texture.id(); } inline Texture& getTexture() { @@ -263,7 +263,6 @@ public: void bindTexture() const; void generateTexture(); void allocateTexture(); - void deleteTexture(); /** * When the caller frees the texture itself, the caller diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp index b117754347ed..f5681ce712d5 100644 --- a/libs/hwui/LayerCache.cpp +++ b/libs/hwui/LayerCache.cpp @@ -112,7 +112,6 @@ Layer* LayerCache::get(RenderState& renderState, const uint32_t width, const uin layer->bindTexture(); layer->setFilter(GL_NEAREST); layer->setWrap(GL_CLAMP_TO_EDGE, false); - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); #if DEBUG_LAYERS dump(); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 92b758de8200..0cd763df78d1 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include #include "OpenGLRenderer.h" #include "DeferredDisplayList.h" @@ -200,6 +201,7 @@ bool OpenGLRenderer::finish() { #if DEBUG_MEMORY_USAGE mCaches.dumpMemoryUsage(); + GPUMemoryTracker::dump(); #else if (Properties::debugLevel & kDebugMemory) { mCaches.dumpMemoryUsage(); @@ -1497,7 +1499,7 @@ void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) { .setMeshTexturedUnitQuad(texture->uvMapper) .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha) .setTransform(*currentSnapshot(), TransformFlags::None) - .setModelViewMapUnitToRectSnap(Rect(texture->width, texture->height)) + .setModelViewMapUnitToRectSnap(Rect(texture->width(), texture->height())) .build(); renderGlop(glop); } @@ -1601,10 +1603,10 @@ void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, Rect src, Rect dst, cons if (!texture) return; const AutoTexture autoCleanup(texture); - Rect uv(std::max(0.0f, src.left / texture->width), - std::max(0.0f, src.top / texture->height), - std::min(1.0f, src.right / texture->width), - std::min(1.0f, src.bottom / texture->height)); + Rect uv(std::max(0.0f, src.left / texture->width()), + std::max(0.0f, src.top / texture->height()), + std::min(1.0f, src.right / texture->width()), + std::min(1.0f, src.bottom / texture->height())); const int textureFillFlags = (bitmap->colorType() == kAlpha_8_SkColorType) ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None; @@ -1977,7 +1979,7 @@ void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text, .setMeshTexturedUnitQuad(nullptr) .setFillShadowTexturePaint(*texture, textShadow.color, *paint, currentSnapshot()->alpha) .setTransform(*currentSnapshot(), TransformFlags::None) - .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width, sy + texture->height)) + .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width(), sy + texture->height())) .build(); renderGlop(glop); } @@ -2316,7 +2318,7 @@ Texture* OpenGLRenderer::getTexture(const SkBitmap* bitmap) { void OpenGLRenderer::drawPathTexture(PathTexture* texture, float x, float y, const SkPaint* paint) { - if (quickRejectSetupScissor(x, y, x + texture->width, y + texture->height)) { + if (quickRejectSetupScissor(x, y, x + texture->width(), y + texture->height())) { return; } @@ -2326,7 +2328,7 @@ void OpenGLRenderer::drawPathTexture(PathTexture* texture, float x, float y, .setMeshTexturedUnitQuad(nullptr) .setFillPathTexturePaint(*texture, *paint, currentSnapshot()->alpha) .setTransform(*currentSnapshot(), TransformFlags::None) - .setModelViewMapUnitToRect(Rect(x, y, x + texture->width, y + texture->height)) + .setModelViewMapUnitToRect(Rect(x, y, x + texture->width(), y + texture->height())) .build(); renderGlop(glop); } diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp index 06ea55ad2eac..bfabc1d4d94c 100644 --- a/libs/hwui/PathCache.cpp +++ b/libs/hwui/PathCache.cpp @@ -185,7 +185,7 @@ void PathCache::operator()(PathDescription& entry, PathTexture*& texture) { void PathCache::removeTexture(PathTexture* texture) { if (texture) { - const uint32_t size = texture->width * texture->height; + const uint32_t size = texture->width() * texture->height(); // If there is a pending task we must wait for it to return // before attempting our cleanup @@ -209,9 +209,7 @@ void PathCache::removeTexture(PathTexture* texture) { ALOGD("Shape deleted, size = %d", size); } - if (texture->id) { - Caches::getInstance().textureState().deleteTexture(texture->id); - } + texture->deleteTexture(); delete texture; } } @@ -248,8 +246,7 @@ PathTexture* PathCache::addTexture(const PathDescription& entry, const SkPath *p drawPath(path, paint, bitmap, left, top, offset, width, height); PathTexture* texture = new PathTexture(Caches::getInstance(), - left, top, offset, width, height, - path->getGenerationID()); + left, top, offset, path->getGenerationID()); generateTexture(entry, &bitmap, texture); return texture; @@ -262,7 +259,7 @@ void PathCache::generateTexture(const PathDescription& entry, SkBitmap* bitmap, // Note here that we upload to a texture even if it's bigger than mMaxSize. // Such an entry in mCache will only be temporary, since it will be evicted // immediately on trim, or on any other Path entering the cache. - uint32_t size = texture->width * texture->height; + uint32_t size = texture->width() * texture->height(); mSize += size; PATH_LOGD("PathCache::get/create: name, size, mSize = %d, %d, %d", texture->id, size, mSize); @@ -280,24 +277,8 @@ void PathCache::clear() { void PathCache::generateTexture(SkBitmap& bitmap, Texture* texture) { ATRACE_NAME("Upload Path Texture"); - SkAutoLockPixels alp(bitmap); - if (!bitmap.readyToDraw()) { - ALOGE("Cannot generate texture from bitmap"); - return; - } - - glGenTextures(1, &texture->id); - - Caches::getInstance().textureState().bindTexture(texture->id); - // Textures are Alpha8 - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - texture->blend = true; - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texture->width, texture->height, 0, - GL_ALPHA, GL_UNSIGNED_BYTE, bitmap.getPixels()); - + texture->upload(bitmap); texture->setFilter(GL_LINEAR); - texture->setWrap(GL_CLAMP_TO_EDGE); } /////////////////////////////////////////////////////////////////////////////// @@ -320,16 +301,12 @@ void PathCache::PathProcessor::onProcess(const sp >& task) { texture->left = left; texture->top = top; texture->offset = offset; - texture->width = width; - texture->height = height; if (width <= mMaxTextureSize && height <= mMaxTextureSize) { SkBitmap* bitmap = new SkBitmap(); drawPath(&t->path, &t->paint, *bitmap, left, top, offset, width, height); t->setResult(bitmap); } else { - texture->width = 0; - texture->height = 0; t->setResult(nullptr); } } diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h index 302e9f856904..18f380fe3f7a 100644 --- a/libs/hwui/PathCache.h +++ b/libs/hwui/PathCache.h @@ -61,13 +61,11 @@ class Caches; */ struct PathTexture: public Texture { PathTexture(Caches& caches, float left, float top, - float offset, int width, int height, int generation) + float offset, int generation) : Texture(caches) , left(left) , top(top) , offset(offset) { - this->width = width; - this->height = height; this->generation = generation; } PathTexture(Caches& caches, int generation) diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp index 83652c6de21f..6f4a6839be4e 100644 --- a/libs/hwui/SkiaShader.cpp +++ b/libs/hwui/SkiaShader.cpp @@ -57,7 +57,7 @@ static inline void bindUniformColor(int slot, FloatColor color) { } static inline void bindTexture(Caches* caches, Texture* texture, GLenum wrapS, GLenum wrapT) { - caches->textureState().bindTexture(texture->id); + caches->textureState().bindTexture(texture->id()); texture->setWrapST(wrapS, wrapT); } @@ -219,8 +219,8 @@ bool tryStoreBitmap(Caches& caches, const SkShader& shader, const Matrix4& model outData->bitmapSampler = (*textureUnit)++; - const float width = outData->bitmapTexture->width; - const float height = outData->bitmapTexture->height; + const float width = outData->bitmapTexture->width(); + const float height = outData->bitmapTexture->height(); description->hasBitmap = true; if (!caches.extensions().hasNPot() diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp index 51f16523966b..f1e28b7dfa40 100644 --- a/libs/hwui/TextDropShadowCache.cpp +++ b/libs/hwui/TextDropShadowCache.cpp @@ -187,13 +187,10 @@ ShadowTexture* TextDropShadowCache::get(const SkPaint* paint, const char* glyphs texture = new ShadowTexture(caches); texture->left = shadow.penX; texture->top = shadow.penY; - texture->width = shadow.width; - texture->height = shadow.height; texture->generation = 0; texture->blend = true; const uint32_t size = shadow.width * shadow.height; - texture->bitmapSize = size; // Don't even try to cache a bitmap that's bigger than the cache if (size < mMaxSize) { @@ -202,15 +199,11 @@ ShadowTexture* TextDropShadowCache::get(const SkPaint* paint, const char* glyphs } } - glGenTextures(1, &texture->id); - - caches.textureState().bindTexture(texture->id); // Textures are Alpha8 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texture->width, texture->height, 0, + texture->upload(GL_ALPHA, shadow.width, shadow.height, GL_ALPHA, GL_UNSIGNED_BYTE, shadow.image); - texture->setFilter(GL_LINEAR); texture->setWrap(GL_CLAMP_TO_EDGE); diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp index 5195b457af2b..8a6b28d86f27 100644 --- a/libs/hwui/Texture.cpp +++ b/libs/hwui/Texture.cpp @@ -14,14 +14,29 @@ * limitations under the License. */ -#include - #include "Caches.h" #include "Texture.h" +#include "utils/TraceUtils.h" + +#include + +#include namespace android { namespace uirenderer { +static int bytesPerPixel(GLint glFormat) { + switch (glFormat) { + case GL_ALPHA: + return 1; + case GL_RGB: + return 3; + case GL_RGBA: + default: + return 4; + } +} + void Texture::setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture, bool force, GLenum renderTarget) { @@ -32,7 +47,7 @@ void Texture::setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture, bool force mWrapT = wrapT; if (bindTexture) { - mCaches.textureState().bindTexture(renderTarget, id); + mCaches.textureState().bindTexture(renderTarget, mId); } glTexParameteri(renderTarget, GL_TEXTURE_WRAP_S, wrapS); @@ -50,7 +65,7 @@ void Texture::setFilterMinMag(GLenum min, GLenum mag, bool bindTexture, bool for mMagFilter = mag; if (bindTexture) { - mCaches.textureState().bindTexture(renderTarget, id); + mCaches.textureState().bindTexture(renderTarget, mId); } if (mipMap && min == GL_LINEAR) min = GL_LINEAR_MIPMAP_LINEAR; @@ -60,8 +75,189 @@ void Texture::setFilterMinMag(GLenum min, GLenum mag, bool bindTexture, bool for } } -void Texture::deleteTexture() const { - mCaches.textureState().deleteTexture(id); +void Texture::deleteTexture() { + mCaches.textureState().deleteTexture(mId); + mId = 0; +} + +bool Texture::updateSize(uint32_t width, uint32_t height, GLint format) { + if (mWidth == width && mHeight == height && mFormat == format) { + return false; + } + mWidth = width; + mHeight = height; + mFormat = format; + notifySizeChanged(mWidth * mHeight * bytesPerPixel(mFormat)); + return true; +} + +void Texture::upload(GLint internalformat, uint32_t width, uint32_t height, + GLenum format, GLenum type, const void* pixels) { + bool needsAlloc = updateSize(width, height, internalformat); + if (!needsAlloc && !pixels) { + return; + } + mCaches.textureState().activateTexture(0); + if (!mId) { + glGenTextures(1, &mId); + needsAlloc = true; + } + mCaches.textureState().bindTexture(GL_TEXTURE_2D, mId); + if (needsAlloc) { + glTexImage2D(GL_TEXTURE_2D, 0, mFormat, mWidth, mHeight, 0, + format, type, pixels); + } else { + glTexSubImage2D(GL_TEXTURE_2D, 0, mFormat, mWidth, mHeight, 0, + format, type, pixels); + } +} + +static void uploadToTexture(bool resize, GLenum format, GLenum type, GLsizei stride, GLsizei bpp, + GLsizei width, GLsizei height, const GLvoid * data) { + + glPixelStorei(GL_UNPACK_ALIGNMENT, bpp); + const bool useStride = stride != width + && Caches::getInstance().extensions().hasUnpackRowLength(); + if ((stride == width) || useStride) { + if (useStride) { + glPixelStorei(GL_UNPACK_ROW_LENGTH, stride); + } + + if (resize) { + glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data); + } else { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data); + } + + if (useStride) { + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + } + } else { + // With OpenGL ES 2.0 we need to copy the bitmap in a temporary buffer + // if the stride doesn't match the width + + GLvoid * temp = (GLvoid *) malloc(width * height * bpp); + if (!temp) return; + + uint8_t * pDst = (uint8_t *)temp; + uint8_t * pSrc = (uint8_t *)data; + for (GLsizei i = 0; i < height; i++) { + memcpy(pDst, pSrc, width * bpp); + pDst += width * bpp; + pSrc += stride * bpp; + } + + if (resize) { + glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, temp); + } else { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, temp); + } + + free(temp); + } +} + +static void uploadSkBitmapToTexture(const SkBitmap& bitmap, + bool resize, GLenum format, GLenum type) { + uploadToTexture(resize, format, type, bitmap.rowBytesAsPixels(), bitmap.bytesPerPixel(), + bitmap.width(), bitmap.height(), bitmap.getPixels()); +} + +static void colorTypeToGlFormatAndType(SkColorType colorType, + GLint* outFormat, GLint* outType) { + switch (colorType) { + case kAlpha_8_SkColorType: + *outFormat = GL_ALPHA; + *outType = GL_UNSIGNED_BYTE; + break; + case kRGB_565_SkColorType: + *outFormat = GL_RGB; + *outType = GL_UNSIGNED_SHORT_5_6_5; + break; + // ARGB_4444 and Index_8 are both upconverted to RGBA_8888 + case kARGB_4444_SkColorType: + case kIndex_8_SkColorType: + case kN32_SkColorType: + *outFormat = GL_RGBA; + *outType = GL_UNSIGNED_BYTE; + break; + default: + LOG_ALWAYS_FATAL("Unsupported bitmap colorType: %d", colorType); + break; + } +} + +void Texture::upload(const SkBitmap& bitmap) { + SkAutoLockPixels alp(bitmap); + + if (!bitmap.readyToDraw()) { + ALOGE("Cannot generate texture from bitmap"); + return; + } + + ATRACE_FORMAT("Upload %ux%u Texture", bitmap.width(), bitmap.height()); + + // We could also enable mipmapping if both bitmap dimensions are powers + // of 2 but we'd have to deal with size changes. Let's keep this simple + const bool canMipMap = mCaches.extensions().hasNPot(); + + // If the texture had mipmap enabled but not anymore, + // force a glTexImage2D to discard the mipmap levels + bool needsAlloc = canMipMap && mipMap && !bitmap.hasHardwareMipMap(); + + if (!mId) { + glGenTextures(1, &mId); + needsAlloc = true; + } + + GLint format, type; + colorTypeToGlFormatAndType(bitmap.colorType(), &format, &type); + + if (updateSize(bitmap.width(), bitmap.height(), format)) { + needsAlloc = true; + } + + blend = !bitmap.isOpaque(); + mCaches.textureState().bindTexture(mId); + + if (CC_UNLIKELY(bitmap.colorType() == kARGB_4444_SkColorType + || bitmap.colorType() == kIndex_8_SkColorType)) { + SkBitmap rgbaBitmap; + rgbaBitmap.allocPixels(SkImageInfo::MakeN32(mWidth, mHeight, + bitmap.alphaType())); + rgbaBitmap.eraseColor(0); + + SkCanvas canvas(rgbaBitmap); + canvas.drawBitmap(bitmap, 0.0f, 0.0f, nullptr); + + uploadSkBitmapToTexture(rgbaBitmap, needsAlloc, format, type); + } else { + uploadSkBitmapToTexture(bitmap, needsAlloc, format, type); + } + + if (canMipMap) { + mipMap = bitmap.hasHardwareMipMap(); + if (mipMap) { + glGenerateMipmap(GL_TEXTURE_2D); + } + } + + if (mFirstFilter) { + setFilter(GL_NEAREST); + } + + if (mFirstWrap) { + setWrap(GL_CLAMP_TO_EDGE); + } +} + +void Texture::wrap(GLuint id, uint32_t width, uint32_t height, GLint format) { + mId = id; + mWidth = width; + mHeight = height; + mFormat = format; + // We're wrapping an existing texture, so don't double count this memory + notifySizeChanged(0); } }; // namespace uirenderer diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h index 1c544b929e64..4e8e6dcf1a77 100644 --- a/libs/hwui/Texture.h +++ b/libs/hwui/Texture.h @@ -17,20 +17,27 @@ #ifndef ANDROID_HWUI_TEXTURE_H #define ANDROID_HWUI_TEXTURE_H +#include "GpuMemoryTracker.h" + #include +#include namespace android { namespace uirenderer { class Caches; class UvMapper; +class Layer; /** * Represents an OpenGL texture. */ -class Texture { +class Texture : public GpuMemoryTracker { public: - Texture(Caches& caches) : mCaches(caches) { } + Texture(Caches& caches) + : GpuMemoryTracker(GpuObjectType::Texture) + , mCaches(caches) + { } virtual ~Texture() { } @@ -53,28 +60,63 @@ public: /** * Convenience method to call glDeleteTextures() on this texture's id. */ - void deleteTexture() const; + void deleteTexture(); /** - * Name of the texture. + * Sets the width, height, and format of the texture along with allocating + * the texture ID. Does nothing if the width, height, and format are already + * the requested values. + * + * The image data is undefined after calling this. */ - GLuint id = 0; + void resize(uint32_t width, uint32_t height, GLint format) { + upload(format, width, height, format, GL_UNSIGNED_BYTE, nullptr); + } + /** - * Generation of the backing bitmap, + * Updates this Texture with the contents of the provided SkBitmap, + * also setting the appropriate width, height, and format. It is not necessary + * to call resize() prior to this. + * + * Note this does not set the generation from the SkBitmap. */ - uint32_t generation = 0; + void upload(const SkBitmap& source); + /** - * Indicates whether the texture requires blending. + * Basically glTexImage2D/glTexSubImage2D. */ - bool blend = false; + void upload(GLint internalformat, uint32_t width, uint32_t height, + GLenum format, GLenum type, const void* pixels); + /** - * Width of the backing bitmap. + * Wraps an existing texture. */ - uint32_t width = 0; + void wrap(GLuint id, uint32_t width, uint32_t height, GLint format); + + GLuint id() const { + return mId; + } + + uint32_t width() const { + return mWidth; + } + + uint32_t height() const { + return mHeight; + } + + GLint format() const { + return mFormat; + } + /** - * Height of the backing bitmap. + * Generation of the backing bitmap, */ - uint32_t height = 0; + uint32_t generation = 0; + /** + * Indicates whether the texture requires blending. + */ + bool blend = false; /** * Indicates whether this texture should be cleaned up after use. */ @@ -100,6 +142,19 @@ public: void* isInUse = nullptr; private: + // TODO: Temporarily grant private access to Layer, remove once + // Layer can be de-tangled from being a dual-purpose render target + // and external texture wrapper + friend class Layer; + + // Returns true if the size changed, false if it was the same + bool updateSize(uint32_t width, uint32_t height, GLint format); + + GLuint mId = 0; + uint32_t mWidth = 0; + uint32_t mHeight = 0; + GLint mFormat = 0; + /** * Last wrap modes set on this texture. */ @@ -120,7 +175,7 @@ private: class AutoTexture { public: - AutoTexture(const Texture* texture) + AutoTexture(Texture* texture) : texture(texture) {} ~AutoTexture() { if (texture && texture->cleanup) { @@ -129,7 +184,7 @@ public: } } - const Texture *const texture; + Texture* const texture; }; // class AutoTexture }; // namespace uirenderer diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp index 21901cf4414b..31bfa3a1ada4 100644 --- a/libs/hwui/TextureCache.cpp +++ b/libs/hwui/TextureCache.cpp @@ -166,7 +166,8 @@ Texture* TextureCache::getCachedTexture(const SkBitmap* bitmap, AtlasUsageType a if (canCache) { texture = new Texture(Caches::getInstance()); texture->bitmapSize = size; - Caches::getInstance().textureState().generateTexture(bitmap, texture, false); + texture->generation = bitmap->getGenerationID(); + texture->upload(*bitmap); mSize += size; TEXTURE_LOGD("TextureCache::get: create texture(%p): name, size, mSize = %d, %d, %d", @@ -179,7 +180,8 @@ Texture* TextureCache::getCachedTexture(const SkBitmap* bitmap, AtlasUsageType a } else if (!texture->isInUse && bitmap->getGenerationID() != texture->generation) { // Texture was in the cache but is dirty, re-upload // TODO: Re-adjust the cache size if the bitmap's dimensions have changed - Caches::getInstance().textureState().generateTexture(bitmap, texture, true); + texture->upload(*bitmap); + texture->generation = bitmap->getGenerationID(); } return texture; @@ -204,7 +206,8 @@ Texture* TextureCache::get(const SkBitmap* bitmap, AtlasUsageType atlasUsageType const uint32_t size = bitmap->rowBytes() * bitmap->height(); texture = new Texture(Caches::getInstance()); texture->bitmapSize = size; - Caches::getInstance().textureState().generateTexture(bitmap, texture, false); + texture->upload(*bitmap); + texture->generation = bitmap->getGenerationID(); texture->cleanup = true; } diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h index 191c8a81fec6..463450c81714 100644 --- a/libs/hwui/TextureCache.h +++ b/libs/hwui/TextureCache.h @@ -25,6 +25,7 @@ #include "Debug.h" #include +#include namespace android { namespace uirenderer { diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp index d2685daa1711..8ba4761c1b2e 100644 --- a/libs/hwui/font/CacheTexture.cpp +++ b/libs/hwui/font/CacheTexture.cpp @@ -111,11 +111,11 @@ CacheBlock* CacheBlock::removeBlock(CacheBlock* head, CacheBlock* blockToRemove) CacheTexture::CacheTexture(uint16_t width, uint16_t height, GLenum format, uint32_t maxQuadCount) : mTexture(Caches::getInstance()) + , mWidth(width) + , mHeight(height) , mFormat(format) , mMaxQuadCount(maxQuadCount) , mCaches(Caches::getInstance()) { - mTexture.width = width; - mTexture.height = height; mTexture.blend = true; mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE, @@ -160,10 +160,7 @@ void CacheTexture::releasePixelBuffer() { delete mPixelBuffer; mPixelBuffer = nullptr; } - if (mTexture.id) { - mCaches.textureState().deleteTexture(mTexture.id); - mTexture.id = 0; - } + mTexture.deleteTexture(); mDirty = false; mCurrentQuad = 0; } @@ -183,22 +180,9 @@ void CacheTexture::allocatePixelBuffer() { mPixelBuffer = PixelBuffer::create(mFormat, getWidth(), getHeight()); } - if (!mTexture.id) { - glGenTextures(1, &mTexture.id); - - mCaches.textureState().bindTexture(mTexture.id); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - // Initialize texture dimensions - glTexImage2D(GL_TEXTURE_2D, 0, mFormat, getWidth(), getHeight(), 0, - mFormat, GL_UNSIGNED_BYTE, nullptr); - - const GLenum filtering = getLinearFiltering() ? GL_LINEAR : GL_NEAREST; - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } + mTexture.resize(mWidth, mHeight, mFormat); + mTexture.setFilter(getLinearFiltering() ? GL_LINEAR : GL_NEAREST); + mTexture.setWrap(GL_CLAMP_TO_EDGE); } bool CacheTexture::upload() { diff --git a/libs/hwui/font/CacheTexture.h b/libs/hwui/font/CacheTexture.h index 6dabc768ce6b..5510666eef86 100644 --- a/libs/hwui/font/CacheTexture.h +++ b/libs/hwui/font/CacheTexture.h @@ -92,11 +92,11 @@ public: bool fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY); inline uint16_t getWidth() const { - return mTexture.width; + return mWidth; } inline uint16_t getHeight() const { - return mTexture.height; + return mHeight; } inline GLenum getFormat() const { @@ -122,7 +122,7 @@ public: GLuint getTextureId() { allocatePixelBuffer(); - return mTexture.id; + return mTexture.id(); } inline bool isDirty() const { @@ -183,6 +183,7 @@ private: PixelBuffer* mPixelBuffer = nullptr; Texture mTexture; + uint32_t mWidth, mHeight; GLenum mFormat; bool mLinearFiltering = false; bool mDirty = false; diff --git a/libs/hwui/renderstate/OffscreenBufferPool.cpp b/libs/hwui/renderstate/OffscreenBufferPool.cpp index 227b6409b893..98c94dfab1c5 100644 --- a/libs/hwui/renderstate/OffscreenBufferPool.cpp +++ b/libs/hwui/renderstate/OffscreenBufferPool.cpp @@ -34,29 +34,22 @@ namespace uirenderer { OffscreenBuffer::OffscreenBuffer(RenderState& renderState, Caches& caches, uint32_t viewportWidth, uint32_t viewportHeight) - : renderState(renderState) + : GpuMemoryTracker(GpuObjectType::OffscreenBuffer) + , renderState(renderState) , viewportWidth(viewportWidth) , viewportHeight(viewportHeight) , texture(caches) { - texture.width = computeIdealDimension(viewportWidth); - texture.height = computeIdealDimension(viewportHeight); + uint32_t width = computeIdealDimension(viewportWidth); + uint32_t height = computeIdealDimension(viewportHeight); + texture.resize(width, height, GL_RGBA); texture.blend = true; - - caches.textureState().activateTexture(0); - glGenTextures(1, &texture.id); - caches.textureState().bindTexture(GL_TEXTURE_2D, texture.id); - - texture.setWrap(GL_CLAMP_TO_EDGE, false, false, GL_TEXTURE_2D); + texture.setWrap(GL_CLAMP_TO_EDGE); // not setting filter on texture, since it's set when drawing, based on transform - - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.width, texture.height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, nullptr); } Rect OffscreenBuffer::getTextureCoordinates() { - const float texX = 1.0f / float(texture.width); - const float texY = 1.0f / float(texture.height); + const float texX = 1.0f / static_cast(texture.width()); + const float texY = 1.0f / static_cast(texture.height()); return Rect(0, viewportHeight * texY, viewportWidth * texX, 0); } @@ -69,8 +62,8 @@ void OffscreenBuffer::updateMeshFromRegion() { size_t count; const android::Rect* rects = safeRegion.getArray(&count); - const float texX = 1.0f / float(texture.width); - const float texY = 1.0f / float(texture.height); + const float texX = 1.0f / float(texture.width()); + const float texY = 1.0f / float(texture.height()); FatVector meshVector(count * 4); // uses heap if more than 64 vertices needed TextureVertex* mesh = &meshVector[0]; @@ -157,8 +150,8 @@ OffscreenBuffer* OffscreenBufferPool::get(RenderState& renderState, OffscreenBuffer* OffscreenBufferPool::resize(OffscreenBuffer* layer, const uint32_t width, const uint32_t height) { RenderState& renderState = layer->renderState; - if (layer->texture.width == OffscreenBuffer::computeIdealDimension(width) - && layer->texture.height == OffscreenBuffer::computeIdealDimension(height)) { + if (layer->texture.width() == OffscreenBuffer::computeIdealDimension(width) + && layer->texture.height() == OffscreenBuffer::computeIdealDimension(height)) { // resize in place layer->viewportWidth = width; layer->viewportHeight = height; diff --git a/libs/hwui/renderstate/OffscreenBufferPool.h b/libs/hwui/renderstate/OffscreenBufferPool.h index 2d8d5295e1f8..94155efcbb0a 100644 --- a/libs/hwui/renderstate/OffscreenBufferPool.h +++ b/libs/hwui/renderstate/OffscreenBufferPool.h @@ -17,10 +17,10 @@ #ifndef ANDROID_HWUI_OFFSCREEN_BUFFER_POOL_H #define ANDROID_HWUI_OFFSCREEN_BUFFER_POOL_H +#include #include "Caches.h" #include "Texture.h" #include "utils/Macros.h" - #include #include @@ -40,7 +40,7 @@ class RenderState; * viewport bounds, since textures are always allocated with width / height as a multiple of 64, for * the purpose of improving reuse. */ -class OffscreenBuffer { +class OffscreenBuffer : GpuMemoryTracker { public: OffscreenBuffer(RenderState& renderState, Caches& caches, uint32_t viewportWidth, uint32_t viewportHeight); @@ -58,7 +58,7 @@ public: static uint32_t computeIdealDimension(uint32_t dimension); - uint32_t getSizeInBytes() { return texture.width * texture.height * 4; } + uint32_t getSizeInBytes() { return texture.objectSize(); } RenderState& renderState; @@ -124,8 +124,8 @@ private: Entry(OffscreenBuffer* layer) : layer(layer) - , width(layer->texture.width) - , height(layer->texture.height) { + , width(layer->texture.width()) + , height(layer->texture.height()) { } static int compare(const Entry& lhs, const Entry& rhs); diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp index 4fa820058fb2..4a1e8fcfedf2 100644 --- a/libs/hwui/renderstate/RenderState.cpp +++ b/libs/hwui/renderstate/RenderState.cpp @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include #include "renderstate/RenderState.h" #include "renderthread/CanvasContext.h" #include "renderthread/EglManager.h" #include "utils/GLUtils.h" - #include namespace android { @@ -40,6 +40,8 @@ RenderState::~RenderState() { void RenderState::onGLContextCreated() { LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil, "State object lifecycle not managed correctly"); + GpuMemoryTracker::onGLContextCreated(); + mBlend = new Blend(); mMeshState = new MeshState(); mScissor = new Scissor(); @@ -106,6 +108,8 @@ void RenderState::onGLContextDestroyed() { mScissor = nullptr; delete mStencil; mStencil = nullptr; + + GpuMemoryTracker::onGLContextDestroyed(); } void RenderState::flush(Caches::FlushMode mode) { @@ -310,7 +314,7 @@ void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix) { texture.texture->setFilter(texture.filter, true, false, texture.target); } - mCaches->textureState().bindTexture(texture.target, texture.texture->id); + mCaches->textureState().bindTexture(texture.target, texture.texture->id()); meshState().enableTexCoordsVertexArray(); meshState().bindTexCoordsVertexPointer(force, vertices.texCoord, vertices.stride); diff --git a/libs/hwui/renderstate/TextureState.cpp b/libs/hwui/renderstate/TextureState.cpp index 1f50f712c267..26ebdee06c08 100644 --- a/libs/hwui/renderstate/TextureState.cpp +++ b/libs/hwui/renderstate/TextureState.cpp @@ -34,134 +34,6 @@ const GLenum kTextureUnits[] = { GL_TEXTURE3 }; -static void uploadToTexture(bool resize, GLenum format, GLenum type, GLsizei stride, GLsizei bpp, - GLsizei width, GLsizei height, const GLvoid * data) { - - glPixelStorei(GL_UNPACK_ALIGNMENT, bpp); - const bool useStride = stride != width - && Caches::getInstance().extensions().hasUnpackRowLength(); - if ((stride == width) || useStride) { - if (useStride) { - glPixelStorei(GL_UNPACK_ROW_LENGTH, stride); - } - - if (resize) { - glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data); - } else { - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data); - } - - if (useStride) { - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - } - } else { - // With OpenGL ES 2.0 we need to copy the bitmap in a temporary buffer - // if the stride doesn't match the width - - GLvoid * temp = (GLvoid *) malloc(width * height * bpp); - if (!temp) return; - - uint8_t * pDst = (uint8_t *)temp; - uint8_t * pSrc = (uint8_t *)data; - for (GLsizei i = 0; i < height; i++) { - memcpy(pDst, pSrc, width * bpp); - pDst += width * bpp; - pSrc += stride * bpp; - } - - if (resize) { - glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, temp); - } else { - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, temp); - } - - free(temp); - } -} - -static void uploadSkBitmapToTexture(const SkBitmap& bitmap, - bool resize, GLenum format, GLenum type) { - uploadToTexture(resize, format, type, bitmap.rowBytesAsPixels(), bitmap.bytesPerPixel(), - bitmap.width(), bitmap.height(), bitmap.getPixels()); -} - -void TextureState::generateTexture(const SkBitmap* bitmap, Texture* texture, bool regenerate) { - SkAutoLockPixels alp(*bitmap); - - if (!bitmap->readyToDraw()) { - ALOGE("Cannot generate texture from bitmap"); - return; - } - - ATRACE_FORMAT("Upload %ux%u Texture", bitmap->width(), bitmap->height()); - - // We could also enable mipmapping if both bitmap dimensions are powers - // of 2 but we'd have to deal with size changes. Let's keep this simple - const bool canMipMap = Caches::getInstance().extensions().hasNPot(); - - // If the texture had mipmap enabled but not anymore, - // force a glTexImage2D to discard the mipmap levels - const bool resize = !regenerate || bitmap->width() != int(texture->width) || - bitmap->height() != int(texture->height) || - (regenerate && canMipMap && texture->mipMap && !bitmap->hasHardwareMipMap()); - - if (!regenerate) { - glGenTextures(1, &texture->id); - } - - texture->generation = bitmap->getGenerationID(); - texture->width = bitmap->width(); - texture->height = bitmap->height(); - - bindTexture(texture->id); - - switch (bitmap->colorType()) { - case kAlpha_8_SkColorType: - uploadSkBitmapToTexture(*bitmap, resize, GL_ALPHA, GL_UNSIGNED_BYTE); - texture->blend = true; - break; - case kRGB_565_SkColorType: - uploadSkBitmapToTexture(*bitmap, resize, GL_RGB, GL_UNSIGNED_SHORT_5_6_5); - texture->blend = false; - break; - case kN32_SkColorType: - uploadSkBitmapToTexture(*bitmap, resize, GL_RGBA, GL_UNSIGNED_BYTE); - // Do this after calling getPixels() to make sure Skia's deferred - // decoding happened - texture->blend = !bitmap->isOpaque(); - break; - case kARGB_4444_SkColorType: - case kIndex_8_SkColorType: { - SkBitmap rgbaBitmap; - rgbaBitmap.allocPixels(SkImageInfo::MakeN32(texture->width, texture->height, - bitmap->alphaType())); - rgbaBitmap.eraseColor(0); - - SkCanvas canvas(rgbaBitmap); - canvas.drawBitmap(*bitmap, 0.0f, 0.0f, nullptr); - - uploadSkBitmapToTexture(rgbaBitmap, resize, GL_RGBA, GL_UNSIGNED_BYTE); - texture->blend = !bitmap->isOpaque(); - break; - } - default: - ALOGW("Unsupported bitmap colorType: %d", bitmap->colorType()); - break; - } - - if (canMipMap) { - texture->mipMap = bitmap->hasHardwareMipMap(); - if (texture->mipMap) { - glGenerateMipmap(GL_TEXTURE_2D); - } - } - - if (!regenerate) { - texture->setFilter(GL_NEAREST); - texture->setWrap(GL_CLAMP_TO_EDGE); - } -} - TextureState::TextureState() : mTextureUnit(0) { glActiveTexture(kTextureUnits[0]); diff --git a/libs/hwui/renderstate/TextureState.h b/libs/hwui/renderstate/TextureState.h index 3a2b85ae2886..ec94d7e9e267 100644 --- a/libs/hwui/renderstate/TextureState.h +++ b/libs/hwui/renderstate/TextureState.h @@ -76,13 +76,6 @@ public: */ void unbindTexture(GLuint texture); - /** - * Generates the texture from a bitmap into the specified texture structure. - * - * @param regenerate If true, the bitmap data is reuploaded into the texture, but - * no new texture is generated. - */ - void generateTexture(const SkBitmap* bitmap, Texture* texture, bool regenerate); private: // total number of texture units available for use static const int kTextureUnitsCount = 4; diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 644f3565216b..968135b4fd6c 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include #include "CanvasContext.h" #include "AnimationContext.h" @@ -497,6 +498,8 @@ void CanvasContext::draw() { mJankTracker.addFrame(*mCurrentFrameInfo); mRenderThread.jankTracker().addFrame(*mCurrentFrameInfo); + + GpuMemoryTracker::onFrameCompleted(); } // Called by choreographer to do an RT-driven animation diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h index edde31e502e0..42cd0ced0cac 100644 --- a/libs/hwui/tests/common/TestUtils.h +++ b/libs/hwui/tests/common/TestUtils.h @@ -197,6 +197,10 @@ public: renderthread::RenderThread::getInstance().queueAndWait(&task); } + static bool isRenderThreadRunning() { + return renderthread::RenderThread::hasInstance(); + } + static SkColor interpolateColor(float fraction, SkColor start, SkColor end); static void drawTextToCanvas(TestCanvas* canvas, const char* text, diff --git a/libs/hwui/tests/macrobench/main.cpp b/libs/hwui/tests/macrobench/main.cpp index 1616a95857d8..02a39501e647 100644 --- a/libs/hwui/tests/macrobench/main.cpp +++ b/libs/hwui/tests/macrobench/main.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include diff --git a/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp b/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp new file mode 100644 index 000000000000..aa1dcb2ea51b --- /dev/null +++ b/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include + +#include "renderthread/EglManager.h" +#include "renderthread/RenderThread.h" +#include "tests/common/TestUtils.h" + +#include + +using namespace android; +using namespace android::uirenderer; +using namespace android::uirenderer::renderthread; + +class TestGPUObject : public GpuMemoryTracker { +public: + TestGPUObject() : GpuMemoryTracker(GpuObjectType::Texture) {} + + void changeSize(int newSize) { + notifySizeChanged(newSize); + } +}; + +// Other tests may have created a renderthread and EGL context. +// This will destroy the EGLContext on RenderThread if it exists so that the +// current thread can spoof being a GPU thread +static void destroyEglContext() { + if (TestUtils::isRenderThreadRunning()) { + TestUtils::runOnRenderThread([](RenderThread& thread) { + thread.eglManager().destroy(); + }); + } +} + +TEST(GpuMemoryTracker, sizeCheck) { + destroyEglContext(); + + GpuMemoryTracker::onGLContextCreated(); + ASSERT_EQ(0, GpuMemoryTracker::getTotalSize(GpuObjectType::Texture)); + ASSERT_EQ(0, GpuMemoryTracker::getInstanceCount(GpuObjectType::Texture)); + { + TestGPUObject myObj; + ASSERT_EQ(1, GpuMemoryTracker::getInstanceCount(GpuObjectType::Texture)); + myObj.changeSize(500); + ASSERT_EQ(500, GpuMemoryTracker::getTotalSize(GpuObjectType::Texture)); + myObj.changeSize(1000); + ASSERT_EQ(1000, GpuMemoryTracker::getTotalSize(GpuObjectType::Texture)); + myObj.changeSize(300); + ASSERT_EQ(300, GpuMemoryTracker::getTotalSize(GpuObjectType::Texture)); + } + ASSERT_EQ(0, GpuMemoryTracker::getTotalSize(GpuObjectType::Texture)); + ASSERT_EQ(0, GpuMemoryTracker::getInstanceCount(GpuObjectType::Texture)); + GpuMemoryTracker::onGLContextDestroyed(); +} diff --git a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp b/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp index e96e9ba55361..5278730a3c9e 100644 --- a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp +++ b/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp @@ -36,8 +36,8 @@ TEST(OffscreenBuffer, construct) { EXPECT_EQ(49u, layer.viewportWidth); EXPECT_EQ(149u, layer.viewportHeight); - EXPECT_EQ(64u, layer.texture.width); - EXPECT_EQ(192u, layer.texture.height); + EXPECT_EQ(64u, layer.texture.width()); + EXPECT_EQ(192u, layer.texture.height()); EXPECT_EQ(64u * 192u * 4u, layer.getSizeInBytes()); }); @@ -100,8 +100,8 @@ TEST(OffscreenBufferPool, resize) { ASSERT_EQ(layer, pool.resize(layer, 60u, 55u)); EXPECT_EQ(60u, layer->viewportWidth); EXPECT_EQ(55u, layer->viewportHeight); - EXPECT_EQ(64u, layer->texture.width); - EXPECT_EQ(64u, layer->texture.height); + EXPECT_EQ(64u, layer->texture.width()); + EXPECT_EQ(64u, layer->texture.height()); // resized to use different object in pool auto layer2 = pool.get(thread.renderState(), 128u, 128u); @@ -110,8 +110,8 @@ TEST(OffscreenBufferPool, resize) { ASSERT_EQ(layer2, pool.resize(layer, 120u, 125u)); EXPECT_EQ(120u, layer2->viewportWidth); EXPECT_EQ(125u, layer2->viewportHeight); - EXPECT_EQ(128u, layer2->texture.width); - EXPECT_EQ(128u, layer2->texture.height); + EXPECT_EQ(128u, layer2->texture.width()); + EXPECT_EQ(128u, layer2->texture.height()); // original allocation now only thing in pool EXPECT_EQ(1u, pool.getCount()); diff --git a/libs/hwui/tests/unit/StringUtilsTests.cpp b/libs/hwui/tests/unit/StringUtilsTests.cpp index 6b2e265a61ff..b60e96c756ec 100644 --- a/libs/hwui/tests/unit/StringUtilsTests.cpp +++ b/libs/hwui/tests/unit/StringUtilsTests.cpp @@ -36,3 +36,18 @@ TEST(StringUtils, advancedBuildSet) { EXPECT_TRUE(collection.has("GL_ext1")); EXPECT_FALSE(collection.has("GL_ext")); // string present, but not in list } + +TEST(StringUtils, sizePrinter) { + std::stringstream os; + os << SizePrinter{500}; + EXPECT_EQ("500.00B", os.str()); + os.str(""); + os << SizePrinter{46080}; + EXPECT_EQ("45.00KiB", os.str()); + os.str(""); + os << SizePrinter{5 * 1024 * 1024 + 520 * 1024}; + EXPECT_EQ("5.51MiB", os.str()); + os.str(""); + os << SizePrinter{2147483647}; + EXPECT_EQ("2048.00MiB", os.str()); +} diff --git a/libs/hwui/utils/StringUtils.h b/libs/hwui/utils/StringUtils.h index 055869f73c26..05a3d5931e5d 100644 --- a/libs/hwui/utils/StringUtils.h +++ b/libs/hwui/utils/StringUtils.h @@ -18,6 +18,8 @@ #include #include +#include +#include namespace android { namespace uirenderer { @@ -34,6 +36,21 @@ public: static unordered_string_set split(const char* spacedList); }; +struct SizePrinter { + int bytes; + friend std::ostream& operator<<(std::ostream& stream, const SizePrinter& d) { + static const char* SUFFIXES[] = {"B", "KiB", "MiB"}; + size_t suffix = 0; + double temp = d.bytes; + while (temp > 1000 && suffix < 2) { + temp /= 1024.0; + suffix++; + } + stream << std::fixed << std::setprecision(2) << temp << SUFFIXES[suffix]; + return stream; + } +}; + } /* namespace uirenderer */ } /* namespace android */ -- cgit v1.2.3-59-g8ed1b From 48a8f431fa52ae2ee25ffba9d20676f03bb710ff Mon Sep 17 00:00:00 2001 From: Chris Craik Date: Fri, 5 Feb 2016 15:59:29 -0800 Subject: Move several property queries to Properties class bug:17478770 This removes a lot of redundant property query code, and puts the queries all in one place, so defining them automatically will be simpler in the future. Change-Id: I0428550e6081f07bc6554ffdf73b22284325abb8 --- libs/hwui/FboCache.cpp | 11 ++--------- libs/hwui/GradientCache.cpp | 17 +---------------- libs/hwui/GradientCache.h | 6 +----- libs/hwui/PatchCache.cpp | 12 ++---------- libs/hwui/PatchCache.h | 2 +- libs/hwui/PathCache.cpp | 15 ++++----------- libs/hwui/PathCache.h | 2 +- libs/hwui/Properties.cpp | 25 +++++++++++++++++++++++-- libs/hwui/Properties.h | 9 +++++++++ libs/hwui/RenderBufferCache.cpp | 18 +++--------------- libs/hwui/RenderBufferCache.h | 4 ---- libs/hwui/TessellationCache.cpp | 18 +----------------- libs/hwui/TessellationCache.h | 8 +------- libs/hwui/TextDropShadowCache.cpp | 38 ++++++++------------------------------ libs/hwui/TextDropShadowCache.h | 10 ++-------- libs/hwui/TextureCache.cpp | 32 ++------------------------------ libs/hwui/TextureCache.h | 13 ++----------- 17 files changed, 63 insertions(+), 177 deletions(-) (limited to 'libs/hwui/TextureCache.cpp') diff --git a/libs/hwui/FboCache.cpp b/libs/hwui/FboCache.cpp index cca3cb7a98f1..b2181b60054f 100644 --- a/libs/hwui/FboCache.cpp +++ b/libs/hwui/FboCache.cpp @@ -27,15 +27,8 @@ namespace uirenderer { // Constructors/destructor /////////////////////////////////////////////////////////////////////////////// -FboCache::FboCache(): mMaxSize(DEFAULT_FBO_CACHE_SIZE) { - char property[PROPERTY_VALUE_MAX]; - if (property_get(PROPERTY_FBO_CACHE_SIZE, property, nullptr) > 0) { - INIT_LOGD(" Setting fbo cache size to %s", property); - mMaxSize = atoi(property); - } else { - INIT_LOGD(" Using default fbo cache size of %d", DEFAULT_FBO_CACHE_SIZE); - } -} +FboCache::FboCache() + : mMaxSize(Properties::fboCacheSize) {} FboCache::~FboCache() { clear(); diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp index e899ac71ff36..044c7cb65718 100644 --- a/libs/hwui/GradientCache.cpp +++ b/libs/hwui/GradientCache.cpp @@ -65,17 +65,9 @@ int GradientCacheEntry::compare(const GradientCacheEntry& lhs, const GradientCac GradientCache::GradientCache(Extensions& extensions) : mCache(LruCache::kUnlimitedCapacity) , mSize(0) - , mMaxSize(MB(DEFAULT_GRADIENT_CACHE_SIZE)) + , mMaxSize(Properties::gradientCacheSize) , mUseFloatTexture(extensions.hasFloatTextures()) , mHasNpot(extensions.hasNPot()){ - char property[PROPERTY_VALUE_MAX]; - if (property_get(PROPERTY_GRADIENT_CACHE_SIZE, property, nullptr) > 0) { - INIT_LOGD(" Setting gradient cache size to %sMB", property); - setMaxSize(MB(atof(property))); - } else { - INIT_LOGD(" Using default gradient cache size of %.2fMB", DEFAULT_GRADIENT_CACHE_SIZE); - } - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); mCache.setOnEntryRemovedListener(this); @@ -97,13 +89,6 @@ uint32_t GradientCache::getMaxSize() { return mMaxSize; } -void GradientCache::setMaxSize(uint32_t maxSize) { - mMaxSize = maxSize; - while (mSize > mMaxSize) { - mCache.removeOldest(); - } -} - /////////////////////////////////////////////////////////////////////////////// // Callbacks /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h index b762ca7d5e5c..dccd45072522 100644 --- a/libs/hwui/GradientCache.h +++ b/libs/hwui/GradientCache.h @@ -122,10 +122,6 @@ public: */ void clear(); - /** - * Sets the maximum size of the cache in bytes. - */ - void setMaxSize(uint32_t maxSize); /** * Returns the maximum size of the cache in bytes. */ @@ -177,7 +173,7 @@ private: LruCache mCache; uint32_t mSize; - uint32_t mMaxSize; + const uint32_t mMaxSize; GLint mMaxTextureSize; bool mUseFloatTexture; diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp index 98812805259e..bd6feb9fc762 100644 --- a/libs/hwui/PatchCache.cpp +++ b/libs/hwui/PatchCache.cpp @@ -32,20 +32,12 @@ namespace uirenderer { PatchCache::PatchCache(RenderState& renderState) : mRenderState(renderState) + , mMaxSize(Properties::patchCacheSize) , mSize(0) , mCache(LruCache::kUnlimitedCapacity) , mMeshBuffer(0) , mFreeBlocks(nullptr) - , mGenerationId(0) { - char property[PROPERTY_VALUE_MAX]; - if (property_get(PROPERTY_PATCH_CACHE_SIZE, property, nullptr) > 0) { - INIT_LOGD(" Setting patch cache size to %skB", property); - mMaxSize = KB(atoi(property)); - } else { - INIT_LOGD(" Using default patch cache size of %.2fkB", DEFAULT_PATCH_CACHE_SIZE); - mMaxSize = KB(DEFAULT_PATCH_CACHE_SIZE); - } -} + , mGenerationId(0) {} PatchCache::~PatchCache() { clear(); diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h index 387f79acf0ec..66ef6a0279ba 100644 --- a/libs/hwui/PatchCache.h +++ b/libs/hwui/PatchCache.h @@ -169,7 +169,7 @@ private: #endif RenderState& mRenderState; - uint32_t mMaxSize; + const uint32_t mMaxSize; uint32_t mSize; LruCache mCache; diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp index bfabc1d4d94c..8f914acc5c76 100644 --- a/libs/hwui/PathCache.cpp +++ b/libs/hwui/PathCache.cpp @@ -135,17 +135,10 @@ static void drawPath(const SkPath *path, const SkPaint* paint, SkBitmap& bitmap, // Cache constructor/destructor /////////////////////////////////////////////////////////////////////////////// -PathCache::PathCache(): - mCache(LruCache::kUnlimitedCapacity), - mSize(0), mMaxSize(MB(DEFAULT_PATH_CACHE_SIZE)) { - char property[PROPERTY_VALUE_MAX]; - if (property_get(PROPERTY_PATH_CACHE_SIZE, property, nullptr) > 0) { - INIT_LOGD(" Setting path cache size to %sMB", property); - mMaxSize = MB(atof(property)); - } else { - INIT_LOGD(" Using default path cache size of %.2fMB", DEFAULT_PATH_CACHE_SIZE); - } - +PathCache::PathCache() + : mCache(LruCache::kUnlimitedCapacity) + , mSize(0) + , mMaxSize(Properties::pathCacheSize) { mCache.setOnEntryRemovedListener(this); GLint maxTextureSize; diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h index 18f380fe3f7a..d2633aa427c5 100644 --- a/libs/hwui/PathCache.h +++ b/libs/hwui/PathCache.h @@ -300,7 +300,7 @@ private: LruCache mCache; uint32_t mSize; - uint32_t mMaxSize; + const uint32_t mMaxSize; GLuint mMaxTextureSize; bool mDebugEnabled; diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp index 083aeb7ed585..bbd8c7226ab2 100644 --- a/libs/hwui/Properties.cpp +++ b/libs/hwui/Properties.cpp @@ -37,7 +37,18 @@ bool Properties::useBufferAge = true; bool Properties::enablePartialUpdates = true; float Properties::textGamma = DEFAULT_TEXT_GAMMA; -int Properties::layerPoolSize = DEFAULT_LAYER_CACHE_SIZE; + +int Properties::fboCacheSize = DEFAULT_FBO_CACHE_SIZE; +int Properties::gradientCacheSize = MB(DEFAULT_GRADIENT_CACHE_SIZE); +int Properties::layerPoolSize = MB(DEFAULT_LAYER_CACHE_SIZE); +int Properties::patchCacheSize = KB(DEFAULT_PATCH_CACHE_SIZE); +int Properties::pathCacheSize = MB(DEFAULT_PATH_CACHE_SIZE); +int Properties::renderBufferCacheSize = MB(DEFAULT_RENDER_BUFFER_CACHE_SIZE); +int Properties::tessellationCacheSize = MB(DEFAULT_VERTEX_CACHE_SIZE); +int Properties::textDropShadowCacheSize = MB(DEFAULT_DROP_SHADOW_CACHE_SIZE); +int Properties::textureCacheSize = MB(DEFAULT_TEXTURE_CACHE_SIZE); + +float Properties::textureCacheFlushRate = DEFAULT_TEXTURE_CACHE_FLUSH_RATE; DebugLevel Properties::debugLevel = kDebugDisabled; OverdrawColorSet Properties::overdrawColorSet = OverdrawColorSet::Default; @@ -79,7 +90,6 @@ bool Properties::load() { bool prevDebugOverdraw = debugOverdraw; StencilClipDebug prevDebugStencilClip = debugStencilClip; - debugOverdraw = false; if (property_get(PROPERTY_DEBUG_OVERDRAW, property, nullptr) > 0) { INIT_LOGD(" Overdraw debug enabled: %s", property); @@ -133,7 +143,18 @@ bool Properties::load() { enablePartialUpdates = property_get_bool(PROPERTY_ENABLE_PARTIAL_UPDATES, true); textGamma = property_get_float(PROPERTY_TEXT_GAMMA, DEFAULT_TEXT_GAMMA); + + fboCacheSize = property_get_int(PROPERTY_FBO_CACHE_SIZE, DEFAULT_FBO_CACHE_SIZE); + gradientCacheSize = MB(property_get_float(PROPERTY_GRADIENT_CACHE_SIZE, DEFAULT_GRADIENT_CACHE_SIZE)); layerPoolSize = MB(property_get_float(PROPERTY_LAYER_CACHE_SIZE, DEFAULT_LAYER_CACHE_SIZE)); + patchCacheSize = KB(property_get_float(PROPERTY_PATCH_CACHE_SIZE, DEFAULT_PATCH_CACHE_SIZE)); + pathCacheSize = MB(property_get_float(PROPERTY_PATH_CACHE_SIZE, DEFAULT_PATH_CACHE_SIZE)); + renderBufferCacheSize = MB(property_get_float(PROPERTY_RENDER_BUFFER_CACHE_SIZE, DEFAULT_RENDER_BUFFER_CACHE_SIZE)); + tessellationCacheSize = MB(property_get_float(PROPERTY_VERTEX_CACHE_SIZE, DEFAULT_VERTEX_CACHE_SIZE)); + textDropShadowCacheSize = MB(property_get_float(PROPERTY_DROP_SHADOW_CACHE_SIZE, DEFAULT_DROP_SHADOW_CACHE_SIZE)); + textureCacheSize = MB(property_get_float(PROPERTY_TEXTURE_CACHE_SIZE, DEFAULT_TEXTURE_CACHE_SIZE)); + textureCacheFlushRate = std::max(0.0f, std::min(1.0f, + property_get_float(PROPERTY_TEXTURE_CACHE_FLUSH_RATE, DEFAULT_TEXTURE_CACHE_FLUSH_RATE))); return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw) diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 88f1dbc98926..3e111516ac63 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -267,7 +267,16 @@ public: static float textGamma; + static int fboCacheSize; + static int gradientCacheSize; static int layerPoolSize; + static int patchCacheSize; + static int pathCacheSize; + static int renderBufferCacheSize; + static int tessellationCacheSize; + static int textDropShadowCacheSize; + static int textureCacheSize; + static float textureCacheFlushRate; static DebugLevel debugLevel; static OverdrawColorSet overdrawColorSet; diff --git a/libs/hwui/RenderBufferCache.cpp b/libs/hwui/RenderBufferCache.cpp index 11d7a6af3a6a..1ac57cdbac0c 100644 --- a/libs/hwui/RenderBufferCache.cpp +++ b/libs/hwui/RenderBufferCache.cpp @@ -40,16 +40,9 @@ namespace uirenderer { // Constructors/destructor /////////////////////////////////////////////////////////////////////////////// -RenderBufferCache::RenderBufferCache(): mSize(0), mMaxSize(MB(DEFAULT_RENDER_BUFFER_CACHE_SIZE)) { - char property[PROPERTY_VALUE_MAX]; - if (property_get(PROPERTY_RENDER_BUFFER_CACHE_SIZE, property, nullptr) > 0) { - INIT_LOGD(" Setting render buffer cache size to %sMB", property); - setMaxSize(MB(atof(property))); - } else { - INIT_LOGD(" Using default render buffer cache size of %.2fMB", - DEFAULT_RENDER_BUFFER_CACHE_SIZE); - } -} +RenderBufferCache::RenderBufferCache() + : mSize(0) + , mMaxSize(Properties::renderBufferCacheSize) {} RenderBufferCache::~RenderBufferCache() { clear(); @@ -67,11 +60,6 @@ uint32_t RenderBufferCache::getMaxSize() { return mMaxSize; } -void RenderBufferCache::setMaxSize(uint32_t maxSize) { - clear(); - mMaxSize = maxSize; -} - /////////////////////////////////////////////////////////////////////////////// // Caching /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/RenderBufferCache.h b/libs/hwui/RenderBufferCache.h index 7f59ec1c48b1..f77f4c95b5ba 100644 --- a/libs/hwui/RenderBufferCache.h +++ b/libs/hwui/RenderBufferCache.h @@ -63,10 +63,6 @@ public: */ void clear(); - /** - * Sets the maximum size of the cache in bytes. - */ - void setMaxSize(uint32_t maxSize); /** * Returns the maximum size of the cache in bytes. */ diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp index fd9fb852171c..14c8f3926e31 100644 --- a/libs/hwui/TessellationCache.cpp +++ b/libs/hwui/TessellationCache.cpp @@ -265,18 +265,9 @@ public: /////////////////////////////////////////////////////////////////////////////// TessellationCache::TessellationCache() - : mSize(0) - , mMaxSize(MB(DEFAULT_VERTEX_CACHE_SIZE)) + : mMaxSize(Properties::tessellationCacheSize) , mCache(LruCache::kUnlimitedCapacity) , mShadowCache(LruCache*>::kUnlimitedCapacity) { - char property[PROPERTY_VALUE_MAX]; - if (property_get(PROPERTY_VERTEX_CACHE_SIZE, property, nullptr) > 0) { - INIT_LOGD(" Setting tessellation cache size to %sMB", property); - setMaxSize(MB(atof(property))); - } else { - INIT_LOGD(" Using default tessellation cache size of %.2fMB", DEFAULT_VERTEX_CACHE_SIZE); - } - mCache.setOnEntryRemovedListener(&mBufferRemovedListener); mShadowCache.setOnEntryRemovedListener(&mBufferPairRemovedListener); mDebugEnabled = Properties::debugLevel & kDebugCaches; @@ -303,13 +294,6 @@ uint32_t TessellationCache::getMaxSize() { return mMaxSize; } -void TessellationCache::setMaxSize(uint32_t maxSize) { - mMaxSize = maxSize; - while (mSize > mMaxSize) { - mCache.removeOldest(); - } -} - /////////////////////////////////////////////////////////////////////////////// // Caching /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/TessellationCache.h b/libs/hwui/TessellationCache.h index 6dcc8120cf48..0bd6365db60f 100644 --- a/libs/hwui/TessellationCache.h +++ b/libs/hwui/TessellationCache.h @@ -131,11 +131,6 @@ public: * Clears the cache. This causes all TessellationBuffers to be deleted. */ void clear(); - - /** - * Sets the maximum size of the cache in bytes. - */ - void setMaxSize(uint32_t maxSize); /** * Returns the maximum size of the cache in bytes. */ @@ -198,8 +193,7 @@ private: Buffer* getOrCreateBuffer(const Description& entry, Tessellator tessellator); - uint32_t mSize; - uint32_t mMaxSize; + const uint32_t mMaxSize; bool mDebugEnabled; diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp index 1707468f169d..fe4b3d7507b2 100644 --- a/libs/hwui/TextDropShadowCache.cpp +++ b/libs/hwui/TextDropShadowCache.cpp @@ -93,36 +93,21 @@ int ShadowText::compare(const ShadowText& lhs, const ShadowText& rhs) { // Constructors/destructor /////////////////////////////////////////////////////////////////////////////// -TextDropShadowCache::TextDropShadowCache(): - mCache(LruCache::kUnlimitedCapacity), - mSize(0), mMaxSize(MB(DEFAULT_DROP_SHADOW_CACHE_SIZE)) { - char property[PROPERTY_VALUE_MAX]; - if (property_get(PROPERTY_DROP_SHADOW_CACHE_SIZE, property, nullptr) > 0) { - INIT_LOGD(" Setting drop shadow cache size to %sMB", property); - setMaxSize(MB(atof(property))); - } else { - INIT_LOGD(" Using default drop shadow cache size of %.2fMB", - DEFAULT_DROP_SHADOW_CACHE_SIZE); - } - - init(); -} +TextDropShadowCache::TextDropShadowCache() + : TextDropShadowCache(Properties::textDropShadowCacheSize) {} -TextDropShadowCache::TextDropShadowCache(uint32_t maxByteSize): - mCache(LruCache::kUnlimitedCapacity), - mSize(0), mMaxSize(maxByteSize) { - init(); +TextDropShadowCache::TextDropShadowCache(uint32_t maxByteSize) + : mCache(LruCache::kUnlimitedCapacity) + , mSize(0) + , mMaxSize(maxByteSize) { + mCache.setOnEntryRemovedListener(this); + mDebugEnabled = Properties::debugLevel & kDebugMoreCaches; } TextDropShadowCache::~TextDropShadowCache() { mCache.clear(); } -void TextDropShadowCache::init() { - mCache.setOnEntryRemovedListener(this); - mDebugEnabled = Properties::debugLevel & kDebugMoreCaches; -} - /////////////////////////////////////////////////////////////////////////////// // Size management /////////////////////////////////////////////////////////////////////////////// @@ -135,13 +120,6 @@ uint32_t TextDropShadowCache::getMaxSize() { return mMaxSize; } -void TextDropShadowCache::setMaxSize(uint32_t maxSize) { - mMaxSize = maxSize; - while (mSize > mMaxSize) { - mCache.removeOldest(); - } -} - /////////////////////////////////////////////////////////////////////////////// // Callbacks /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/TextDropShadowCache.h b/libs/hwui/TextDropShadowCache.h index c4f3c5d96786..cf647882e5a7 100644 --- a/libs/hwui/TextDropShadowCache.h +++ b/libs/hwui/TextDropShadowCache.h @@ -147,10 +147,6 @@ public: mRenderer = &fontRenderer; } - /** - * Sets the maximum size of the cache in bytes. - */ - void setMaxSize(uint32_t maxSize); /** * Returns the maximum size of the cache in bytes. */ @@ -161,13 +157,11 @@ public: uint32_t getSize(); private: - void init(); - LruCache mCache; uint32_t mSize; - uint32_t mMaxSize; - FontRenderer* mRenderer; + const uint32_t mMaxSize; + FontRenderer* mRenderer = nullptr; bool mDebugEnabled; }; // class TextDropShadowCache diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp index 31bfa3a1ada4..ade8600ab78b 100644 --- a/libs/hwui/TextureCache.cpp +++ b/libs/hwui/TextureCache.cpp @@ -35,26 +35,9 @@ namespace uirenderer { TextureCache::TextureCache() : mCache(LruCache::kUnlimitedCapacity) , mSize(0) - , mMaxSize(MB(DEFAULT_TEXTURE_CACHE_SIZE)) - , mFlushRate(DEFAULT_TEXTURE_CACHE_FLUSH_RATE) + , mMaxSize(Properties::textureCacheSize) + , mFlushRate(Properties::textureCacheFlushRate) , mAssetAtlas(nullptr) { - char property[PROPERTY_VALUE_MAX]; - if (property_get(PROPERTY_TEXTURE_CACHE_SIZE, property, nullptr) > 0) { - INIT_LOGD(" Setting texture cache size to %sMB", property); - setMaxSize(MB(atof(property))); - } else { - INIT_LOGD(" Using default texture cache size of %.2fMB", DEFAULT_TEXTURE_CACHE_SIZE); - } - - if (property_get(PROPERTY_TEXTURE_CACHE_FLUSH_RATE, property, nullptr) > 0) { - float flushRate = atof(property); - INIT_LOGD(" Setting texture cache flush rate to %.2f%%", flushRate * 100.0f); - setFlushRate(flushRate); - } else { - INIT_LOGD(" Using default texture cache flush rate of %.2f%%", - DEFAULT_TEXTURE_CACHE_FLUSH_RATE * 100.0f); - } - mCache.setOnEntryRemovedListener(this); glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); @@ -79,17 +62,6 @@ uint32_t TextureCache::getMaxSize() { return mMaxSize; } -void TextureCache::setMaxSize(uint32_t maxSize) { - mMaxSize = maxSize; - while (mSize > mMaxSize) { - mCache.removeOldest(); - } -} - -void TextureCache::setFlushRate(float flushRate) { - mFlushRate = std::max(0.0f, std::min(1.0f, flushRate)); -} - /////////////////////////////////////////////////////////////////////////////// // Callbacks /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h index 463450c81714..a4317cee73fd 100644 --- a/libs/hwui/TextureCache.h +++ b/libs/hwui/TextureCache.h @@ -108,10 +108,6 @@ public: */ void clear(); - /** - * Sets the maximum size of the cache in bytes. - */ - void setMaxSize(uint32_t maxSize); /** * Returns the maximum size of the cache in bytes. */ @@ -126,11 +122,6 @@ public: * is defined by the flush rate. */ void flush(); - /** - * Indicates the percentage of the cache to retain when a - * memory trim is requested (see Caches::flush). - */ - void setFlushRate(float flushRate); void setAssetAtlas(AssetAtlas* assetAtlas); @@ -148,10 +139,10 @@ private: LruCache mCache; uint32_t mSize; - uint32_t mMaxSize; + const uint32_t mMaxSize; GLint mMaxTextureSize; - float mFlushRate; + const float mFlushRate; bool mDebugEnabled; -- cgit v1.2.3-59-g8ed1b