diff options
-rw-r--r-- | libs/hwui/Android.mk | 8 | ||||
-rw-r--r-- | libs/hwui/Caches.cpp | 7 | ||||
-rw-r--r-- | libs/hwui/FontRenderer.cpp | 14 | ||||
-rw-r--r-- | libs/hwui/FontRenderer.h | 11 | ||||
-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 |
8 files changed, 215 insertions, 1 deletions
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 50801a4702d9..4e9765d64495 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 6d28c5294911..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> @@ -212,6 +215,10 @@ void Caches::dumpMemoryUsage(String8 &log) { 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 1cd708f3ce46..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, diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h index ecfa612ce30e..1e59a966750e 100644 --- a/libs/hwui/FontRenderer.h +++ b/libs/hwui/FontRenderer.h @@ -21,6 +21,9 @@ #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> @@ -136,6 +139,10 @@ public: uint32_t getSize() const; void dumpMemoryUsage(String8& log) const; +#ifdef BUGREPORT_FONT_CACHE_USAGE + FontCacheHistoryTracker& historyTracker() { return mHistoryTracker; } +#endif + private: friend class Font; @@ -205,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/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 |