diff options
| -rw-r--r-- | libs/hwui/Android.mk | 8 | ||||
| -rw-r--r-- | libs/hwui/Caches.cpp | 17 | ||||
| -rw-r--r-- | libs/hwui/FontRenderer.cpp | 71 | ||||
| -rw-r--r-- | libs/hwui/FontRenderer.h | 19 | ||||
| -rw-r--r-- | libs/hwui/GammaFontRenderer.h | 14 | ||||
| -rw-r--r-- | libs/hwui/font/CacheTexture.cpp | 12 | ||||
| -rw-r--r-- | libs/hwui/font/CacheTexture.h | 2 | ||||
| -rw-r--r-- | libs/hwui/font/Font.cpp | 8 | ||||
| -rw-r--r-- | libs/hwui/font/FontCacheHistoryTracker.cpp | 100 | ||||
| -rw-r--r-- | libs/hwui/font/FontCacheHistoryTracker.h | 64 | ||||
| -rw-r--r-- | libs/hwui/renderthread/CanvasContext.cpp | 4 |
11 files changed, 303 insertions, 16 deletions
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 366ef716c109..74b474eef371 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -3,6 +3,7 @@ include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk HWUI_NEW_OPS := true +BUGREPORT_FONT_CACHE_USAGE := true # Enables fine-grained GLES error checking # If set to true, every GLES call is wrapped & error checked @@ -135,6 +136,13 @@ ifeq (true, $(HWUI_NEW_OPS)) endif +ifeq (true, $(BUGREPORT_FONT_CACHE_USAGE)) + hwui_src_files += \ + font/FontCacheHistoryTracker.cpp + hwui_cflags += -DBUGREPORT_FONT_CACHE_USAGE +endif + + ifndef HWUI_COMPILE_SYMBOLS hwui_cflags += -fvisibility=hidden endif diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index 949ad450d5f7..a8ced9b2597b 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -21,6 +21,9 @@ #include "Properties.h" #include "renderstate/RenderState.h" #include "ShadowTessellator.h" +#ifdef BUGREPORT_FONT_CACHE_USAGE +#include "font/FontCacheHistoryTracker.h" +#endif #include "utils/GLUtils.h" #include <cutils/properties.h> @@ -195,12 +198,7 @@ void Caches::dumpMemoryUsage(String8 &log) { log.appendFormat(" PatchCache %8d / %8d\n", patchCache.getSize(), patchCache.getMaxSize()); - const uint32_t sizeA8 = fontRenderer.getFontRendererSize(GL_ALPHA); - const uint32_t sizeRGBA = fontRenderer.getFontRendererSize(GL_RGBA); - log.appendFormat(" FontRenderer A8 %8d / %8d\n", sizeA8, sizeA8); - log.appendFormat(" FontRenderer RGBA %8d / %8d\n", sizeRGBA, sizeRGBA); - log.appendFormat(" FontRenderer total %8d / %8d\n", sizeA8 + sizeRGBA, - sizeA8 + sizeRGBA); + fontRenderer.dumpMemoryUsage(log); log.appendFormat("Other:\n"); log.appendFormat(" FboCache %8d / %8d\n", @@ -213,11 +211,14 @@ void Caches::dumpMemoryUsage(String8 &log) { total += tessellationCache.getSize(); total += dropShadowCache.getSize(); total += patchCache.getSize(); - total += fontRenderer.getFontRendererSize(GL_ALPHA); - total += fontRenderer.getFontRendererSize(GL_RGBA); + total += fontRenderer.getSize(); log.appendFormat("Total memory usage:\n"); log.appendFormat(" %d bytes, %.2f MB\n", total, total / 1024.0f / 1024.0f); + +#ifdef BUGREPORT_FONT_CACHE_USAGE + fontRenderer.getFontRenderer().historyTracker().dump(log); +#endif } /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index 276c18d0d3f9..681cf55066b4 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -168,10 +168,17 @@ void FontRenderer::flushAllAndInvalidate() { for (uint32_t i = 0; i < mACacheTextures.size(); i++) { mACacheTextures[i]->init(); + +#ifdef BUGREPORT_FONT_CACHE_USAGE + mHistoryTracker.glyphsCleared(mACacheTextures[i]); +#endif } for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) { mRGBACacheTextures[i]->init(); +#ifdef BUGREPORT_FONT_CACHE_USAGE + mHistoryTracker.glyphsCleared(mRGBACacheTextures[i]); +#endif } mDrawn = false; @@ -183,6 +190,9 @@ void FontRenderer::flushLargeCaches(std::vector<CacheTexture*>& cacheTextures) { CacheTexture* cacheTexture = cacheTextures[i]; if (cacheTexture->getPixelBuffer()) { cacheTexture->init(); +#ifdef BUGREPORT_FONT_CACHE_USAGE + mHistoryTracker.glyphsCleared(cacheTexture); +#endif LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts); while (it.next()) { it.value()->invalidateTextureCache(cacheTexture); @@ -385,6 +395,10 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp } cachedGlyph->mIsValid = true; + +#ifdef BUGREPORT_FONT_CACHE_USAGE + mHistoryTracker.glyphUploaded(cacheTexture, startX, startY, glyph.fWidth, glyph.fHeight); +#endif } CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format, @@ -747,19 +761,68 @@ static uint32_t calculateCacheSize(const std::vector<CacheTexture*>& cacheTextur return size; } -uint32_t FontRenderer::getCacheSize(GLenum format) const { +static uint32_t calculateFreeCacheSize(const std::vector<CacheTexture*>& cacheTextures) { + uint32_t size = 0; + for (uint32_t i = 0; i < cacheTextures.size(); i++) { + CacheTexture* cacheTexture = cacheTextures[i]; + if (cacheTexture && cacheTexture->getPixelBuffer()) { + size += cacheTexture->calculateFreeMemory(); + } + } + return size; +} + +const std::vector<CacheTexture*>& FontRenderer::cacheTexturesForFormat(GLenum format) const { switch (format) { case GL_ALPHA: { - return calculateCacheSize(mACacheTextures); + return mACacheTextures; } case GL_RGBA: { - return calculateCacheSize(mRGBACacheTextures); + return mRGBACacheTextures; } default: { - return 0; + LOG_ALWAYS_FATAL("Unsupported format: %d", format); + // Impossible to hit this, but the compiler doesn't know that + return *(new std::vector<CacheTexture*>()); } } } +static void dumpTextures(String8& log, const char* tag, + const std::vector<CacheTexture*>& cacheTextures) { + for (uint32_t i = 0; i < cacheTextures.size(); i++) { + CacheTexture* cacheTexture = cacheTextures[i]; + if (cacheTexture && cacheTexture->getPixelBuffer()) { + uint32_t free = cacheTexture->calculateFreeMemory(); + uint32_t total = cacheTexture->getPixelBuffer()->getSize(); + log.appendFormat(" %-4s texture %d %8d / %8d\n", tag, i, total - free, total); + } + } +} + +void FontRenderer::dumpMemoryUsage(String8& log) const { + const uint32_t sizeA8 = getCacheSize(GL_ALPHA); + const uint32_t usedA8 = sizeA8 - getFreeCacheSize(GL_ALPHA); + const uint32_t sizeRGBA = getCacheSize(GL_RGBA); + const uint32_t usedRGBA = sizeRGBA - getFreeCacheSize(GL_RGBA); + log.appendFormat(" FontRenderer A8 %8d / %8d\n", usedA8, sizeA8); + dumpTextures(log, "A8", cacheTexturesForFormat(GL_ALPHA)); + log.appendFormat(" FontRenderer RGBA %8d / %8d\n", usedRGBA, sizeRGBA); + dumpTextures(log, "RGBA", cacheTexturesForFormat(GL_RGBA)); + log.appendFormat(" FontRenderer total %8d / %8d\n", usedA8 + usedRGBA, sizeA8 + sizeRGBA); +} + +uint32_t FontRenderer::getCacheSize(GLenum format) const { + return calculateCacheSize(cacheTexturesForFormat(format)); +} + +uint32_t FontRenderer::getFreeCacheSize(GLenum format) const { + return calculateFreeCacheSize(cacheTexturesForFormat(format)); +} + +uint32_t FontRenderer::getSize() const { + return getCacheSize(GL_ALPHA) + getCacheSize(GL_RGBA); +} + }; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h index e10a81b8ccd8..504dce862f71 100644 --- a/libs/hwui/FontRenderer.h +++ b/libs/hwui/FontRenderer.h @@ -21,8 +21,12 @@ #include "font/CacheTexture.h" #include "font/CachedGlyphInfo.h" #include "font/Font.h" +#ifdef BUGREPORT_FONT_CACHE_USAGE +#include "font/FontCacheHistoryTracker.h" +#endif #include <utils/LruCache.h> +#include <utils/String8.h> #include <utils/StrongPointer.h> #include <SkPaint.h> @@ -132,7 +136,12 @@ public: mLinearFiltering = linearFiltering; } - uint32_t getCacheSize(GLenum format) const; + uint32_t getSize() const; + void dumpMemoryUsage(String8& log) const; + +#ifdef BUGREPORT_FONT_CACHE_USAGE + FontCacheHistoryTracker& historyTracker() { return mHistoryTracker; } +#endif private: friend class Font; @@ -175,6 +184,10 @@ private: mUploadTexture = true; } + const std::vector<CacheTexture*>& cacheTexturesForFormat(GLenum format) const; + uint32_t getCacheSize(GLenum format) const; + uint32_t getFreeCacheSize(GLenum format) const; + uint32_t mSmallCacheWidth; uint32_t mSmallCacheHeight; uint32_t mLargeCacheWidth; @@ -199,6 +212,10 @@ private: bool mLinearFiltering; +#ifdef BUGREPORT_FONT_CACHE_USAGE + FontCacheHistoryTracker mHistoryTracker; +#endif + #ifdef ANDROID_ENABLE_RENDERSCRIPT // RS constructs RSC::sp<RSC::RS> mRs; diff --git a/libs/hwui/GammaFontRenderer.h b/libs/hwui/GammaFontRenderer.h index 5813e7f717ee..bd27a1a72060 100644 --- a/libs/hwui/GammaFontRenderer.h +++ b/libs/hwui/GammaFontRenderer.h @@ -22,6 +22,8 @@ #include <SkPaint.h> +#include <utils/String8.h> + namespace android { namespace uirenderer { @@ -46,8 +48,16 @@ public: return *mRenderer; } - uint32_t getFontRendererSize(GLenum format) const { - return mRenderer ? mRenderer->getCacheSize(format) : 0; + void dumpMemoryUsage(String8& log) const { + if (mRenderer) { + mRenderer->dumpMemoryUsage(log); + } else { + log.appendFormat("FontRenderer doesn't exist.\n"); + } + } + + uint32_t getSize() const { + return mRenderer ? mRenderer->getSize() : 0; } void endPrecaching(); diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp index 8ba4761c1b2e..4b13814bfdc6 100644 --- a/libs/hwui/font/CacheTexture.cpp +++ b/libs/hwui/font/CacheTexture.cpp @@ -324,5 +324,17 @@ bool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_ return false; } +uint32_t CacheTexture::calculateFreeMemory() const { + CacheBlock* cacheBlock = mCacheBlocks; + uint32_t free = 0; + // currently only two formats are supported: GL_ALPHA or GL_RGBA; + uint32_t bpp = mFormat == GL_RGBA ? 4 : 1; + while (cacheBlock) { + free += bpp * cacheBlock->mWidth * cacheBlock->mHeight; + cacheBlock = cacheBlock->mNext; + } + return free; +} + }; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/font/CacheTexture.h b/libs/hwui/font/CacheTexture.h index 4dfb41dafcc7..6750a8ae11cf 100644 --- a/libs/hwui/font/CacheTexture.h +++ b/libs/hwui/font/CacheTexture.h @@ -178,6 +178,8 @@ public: return mCurrentQuad == mMaxQuadCount; } + uint32_t calculateFreeMemory() const; + private: void setDirty(bool dirty); diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp index 8e04c8715f62..a95454a4c010 100644 --- a/libs/hwui/font/Font.cpp +++ b/libs/hwui/font/Font.cpp @@ -408,9 +408,15 @@ void Font::render(const SkPaint* paint, const glyph_t* glyphs, if (cachedGlyph->mIsValid && cachedGlyph->mCacheTexture) { int penX = x + (int) roundf(positions[(glyphsCount << 1)]); int penY = y + (int) roundf(positions[(glyphsCount << 1) + 1]); - +#ifdef BUGREPORT_FONT_CACHE_USAGE + mState->historyTracker().glyphRendered(cachedGlyph, penX, penY); +#endif (*this.*render)(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH, bounds, positions); + } else { +#ifdef BUGREPORT_FONT_CACHE_USAGE + mState->historyTracker().glyphRendered(cachedGlyph, -1, -1); +#endif } glyphsCount++; diff --git a/libs/hwui/font/FontCacheHistoryTracker.cpp b/libs/hwui/font/FontCacheHistoryTracker.cpp new file mode 100644 index 000000000000..a2bfb27535e5 --- /dev/null +++ b/libs/hwui/font/FontCacheHistoryTracker.cpp @@ -0,0 +1,100 @@ +/* + * 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 "FontCacheHistoryTracker.h" + +#include "CachedGlyphInfo.h" +#include "CacheTexture.h" + +namespace android { +namespace uirenderer { + +void FontCacheHistoryTracker::dumpCachedGlyph(String8& log, const CachedGlyph& glyph) { + log.appendFormat("glyph (texture %p, position: (%d, %d), size: %dx%d, gen: %d)", glyph.texture, + glyph.startX, glyph.startY, glyph.bitmapW, glyph.bitmapH, glyph.generation); +} + +void FontCacheHistoryTracker::dumpRenderEntry(String8& log, const RenderEntry& entry) { + if (entry.penX == -1 && entry.penY == -1) { + log.appendFormat(" glyph skipped in gen: %d\n", entry.glyph.generation); + } else { + log.appendFormat(" rendered "); + dumpCachedGlyph(log, entry.glyph); + log.appendFormat(" at (%d, %d)\n", entry.penX, entry.penY); + } +} + +void FontCacheHistoryTracker::dumpUploadEntry(String8& log, const CachedGlyph& glyph) { + if (glyph.bitmapW == 0 && glyph.bitmapH == 0) { + log.appendFormat(" cleared cachetexture %p in gen %d\n", glyph.texture, + glyph.generation); + } else { + log.appendFormat(" uploaded "); + dumpCachedGlyph(log, glyph); + log.appendFormat("\n"); + } +} + +void FontCacheHistoryTracker::dump(String8& log) const { + log.appendFormat("FontCacheHistory: \n"); + log.appendFormat(" Upload history: \n"); + for (size_t i = 0; i < mUploadHistory.size(); i++) { + dumpUploadEntry(log, mUploadHistory[i]); + } + log.appendFormat(" Render history: \n"); + for (size_t i = 0; i < mRenderHistory.size(); i++) { + dumpRenderEntry(log, mRenderHistory[i]); + } +} + +void FontCacheHistoryTracker::glyphRendered(CachedGlyphInfo* glyphInfo, int penX, int penY) { + RenderEntry& entry = mRenderHistory.next(); + entry.glyph.generation = generation; + entry.glyph.texture = glyphInfo->mCacheTexture; + entry.glyph.startX = glyphInfo->mStartX; + entry.glyph.startY = glyphInfo->mStartY; + entry.glyph.bitmapW = glyphInfo->mBitmapWidth; + entry.glyph.bitmapH = glyphInfo->mBitmapHeight; + entry.penX = penX; + entry.penY = penY; +} + +void FontCacheHistoryTracker::glyphUploaded(CacheTexture* texture, uint32_t x, uint32_t y, + uint16_t glyphW, uint16_t glyphH) { + CachedGlyph& glyph = mUploadHistory.next(); + glyph.generation = generation; + glyph.texture = texture; + glyph.startX = x; + glyph.startY = y; + glyph.bitmapW = glyphW; + glyph.bitmapH = glyphH; +} + +void FontCacheHistoryTracker::glyphsCleared(CacheTexture* texture) { + CachedGlyph& glyph = mUploadHistory.next(); + glyph.generation = generation; + glyph.texture = texture; + glyph.startX = 0; + glyph.startY = 0; + glyph.bitmapW = 0; + glyph.bitmapH = 0; +} + +void FontCacheHistoryTracker::frameCompleted() { + generation++; +} +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/font/FontCacheHistoryTracker.h b/libs/hwui/font/FontCacheHistoryTracker.h new file mode 100644 index 000000000000..f1d9b9f10dc0 --- /dev/null +++ b/libs/hwui/font/FontCacheHistoryTracker.h @@ -0,0 +1,64 @@ +/* + * 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 "../utils/RingBuffer.h" + +#include <utils/String8.h> + +namespace android { +namespace uirenderer { + +class CacheTexture; +struct CachedGlyphInfo; + +// Tracks glyph uploads and recent rendered/skipped glyphs, so it can give an idea +// what a missing character is: skipped glyph, wrong coordinates in cache texture etc. +class FontCacheHistoryTracker { +public: + void glyphRendered(CachedGlyphInfo*, int penX, int penY); + void glyphUploaded(CacheTexture*, uint32_t x, uint32_t y, uint16_t glyphW, uint16_t glyphH); + void glyphsCleared(CacheTexture*); + void frameCompleted(); + + void dump(String8& log) const; +private: + struct CachedGlyph { + void* texture; + uint16_t generation; + uint16_t startX; + uint16_t startY; + uint16_t bitmapW; + uint16_t bitmapH; + }; + + struct RenderEntry { + CachedGlyph glyph; + int penX; + int penY; + }; + + static void dumpCachedGlyph(String8& log, const CachedGlyph& glyph); + static void dumpRenderEntry(String8& log, const RenderEntry& entry); + static void dumpUploadEntry(String8& log, const CachedGlyph& glyph); + + RingBuffer<RenderEntry, 300> mRenderHistory; + RingBuffer<CachedGlyph, 120> mUploadHistory; + uint16_t generation = 0; +}; + +}; // namespace uirenderer +}; // namespace android
\ No newline at end of file diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 70b9a436dee2..975ac8368e3d 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -608,6 +608,10 @@ void CanvasContext::draw() { } GpuMemoryTracker::onFrameCompleted(); +#ifdef BUGREPORT_FONT_CACHE_USAGE + caches.fontRenderer.getFontRenderer().historyTracker().frameCompleted(); +#endif + } // Called by choreographer to do an RT-driven animation |