From 4ff0cf4b83605bff630c4e6f1fabe4f72a3f93a1 Mon Sep 17 00:00:00 2001 From: Romain Guy Date: Mon, 6 Aug 2012 14:51:10 -0700 Subject: [PATCH] Add new debug tool to track hardware layers updates You can setprop debug.hwui.show_layers_updates true to flash hw layers in green when they update. This is also a setting in the Dev. section of the settings app. Change-Id: Ibe1d63a4f81567dc1d590c9b088d2e7505df8abf --- core/java/android/view/HardwareRenderer.java | 14 +++- graphics/java/android/graphics/Bitmap.java | 10 +-- libs/hwui/Caches.cpp | 15 ++-- libs/hwui/Caches.h | 2 + libs/hwui/LayerRenderer.cpp | 10 --- libs/hwui/OpenGLRenderer.cpp | 76 +++++--------------- libs/hwui/Patch.cpp | 4 -- libs/hwui/Properties.h | 14 ++-- 8 files changed, 59 insertions(+), 86 deletions(-) diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index 8236cd7cf3ae4..188fede7ddd3e 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -135,7 +135,19 @@ public abstract class HardwareRenderer { * @hide */ public static final String DEBUG_DIRTY_REGIONS_PROPERTY = "debug.hwui.show_dirty_regions"; - + + /** + * Turn on to flash hardware layers when they update. + * + * Possible values: + * "true", to enable hardware layers updates debugging + * "false", to disable hardware layers updates debugging + * + * @hide + */ + public static final String DEBUG_SHOW_LAYERS_UPDATES_PROPERTY = + "debug.hwui.show_layers_updates"; + /** * A process can set this flag to false to prevent the use of hardware * rendering. diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index 128adcbf53a20..6ba57809f3e67 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -881,15 +881,17 @@ public final class Bitmap implements Parcelable { * (128, 128, 0, 0).

* *

This method always returns false if {@link #getConfig()} is - * {@link Bitmap.Config#ALPHA_8} or {@link Bitmap.Config#RGB_565}.

+ * {@link Bitmap.Config#RGB_565}.

+ * + *

This method only returns true if {@link #hasAlpha()} returns true. + * A bitmap with no alpha channel can be used both as a pre-multiplied and + * as a non pre-multiplied bitmap.

* * @return true if the underlying pixels have been pre-multiplied, false * otherwise */ public final boolean isPremultiplied() { - final Config config = getConfig(); - //noinspection deprecation - return config == Config.ARGB_8888 || config == Config.ARGB_4444; + return getConfig() != Config.RGB_565 && hasAlpha(); } /** Returns the bitmap's width */ diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index aa2bc3f674190..0ed4888ac7d3f 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -52,13 +52,10 @@ Caches::Caches(): Singleton(), mInitialized(false) { initFont(); initExtensions(); initConstraints(); + initProperties(); mDebugLevel = readDebugLevel(); ALOGD("Enabling debug mode %d", mDebugLevel); - -#if RENDER_LAYERS_AS_REGIONS - INIT_LOGD("Layers will be composited as regions"); -#endif } void Caches::init() { @@ -126,6 +123,16 @@ void Caches::initConstraints() { glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); } +void Caches::initProperties() { + char property[PROPERTY_VALUE_MAX]; + if (property_get(PROPERTY_DEBUG_LAYERS_UPDATES, property, NULL) > 0) { + INIT_LOGD(" Layers updates debug enabled: %s", property); + debugLayersUpdates = !strcmp(property, "true"); + } else { + debugLayersUpdates = false; + } +} + void Caches::terminate() { if (!mInitialized) return; diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h index ad1098c9b550e..f4f56d6e594bf 100644 --- a/libs/hwui/Caches.h +++ b/libs/hwui/Caches.h @@ -236,6 +236,7 @@ public: // Misc GLint maxTextureSize; + bool debugLayersUpdates; TextureCache textureCache; LayerCache layerCache; @@ -267,6 +268,7 @@ private: void initFont(); void initExtensions(); void initConstraints(); + void initProperties(); static void eventMarkNull(GLsizei length, const GLchar* marker) { } static void startMarkNull(GLsizei length, const GLchar* marker) { } diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp index 41a5f0d4ba847..f81640b22b376 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -45,7 +45,6 @@ int LayerRenderer::prepareDirty(float left, float top, float right, float bottom const float width = mLayer->layer.getWidth(); const float height = mLayer->layer.getHeight(); -#if RENDER_LAYERS_AS_REGIONS Rect dirty(left, top, right, bottom); if (dirty.isEmpty() || (dirty.left <= 0 && dirty.top <= 0 && dirty.right >= width && dirty.bottom >= height)) { @@ -58,9 +57,6 @@ int LayerRenderer::prepareDirty(float left, float top, float right, float bottom } return OpenGLRenderer::prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, opaque); -#else - return OpenGLRenderer::prepareDirty(0.0f, 0.0f, width, height, opaque); -#endif } void LayerRenderer::finish() { @@ -87,14 +83,10 @@ bool LayerRenderer::hasLayer() { } Region* LayerRenderer::getRegion() { -#if RENDER_LAYERS_AS_REGIONS if (getSnapshot()->flags & Snapshot::kFlagFboTarget) { return OpenGLRenderer::getRegion(); } return &mLayer->region; -#else - return OpenGLRenderer::getRegion(); -#endif } // TODO: This implementation is flawed and can generate T-junctions @@ -105,7 +97,6 @@ Region* LayerRenderer::getRegion() { // In practice, T-junctions do not appear often so this has yet // to be fixed. void LayerRenderer::generateMesh() { -#if RENDER_LAYERS_AS_REGIONS if (mLayer->region.isRect() || mLayer->region.isEmpty()) { if (mLayer->mesh) { delete mLayer->mesh; @@ -172,7 +163,6 @@ void LayerRenderer::generateMesh() { indices[index + 5] = quad + 3; // bottom-right } } -#endif } /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index a1da87868701a..580d6b58bd43e 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -321,13 +321,11 @@ status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) { Rect clip(*mSnapshot->clipRect); clip.snapToPixelBoundaries(); -#if RENDER_LAYERS_AS_REGIONS // Since we don't know what the functor will draw, let's dirty // tne entire clip region if (hasLayer()) { dirtyLayerUnchecked(clip, getRegion()); } -#endif DrawGlInfo info; info.clipLeft = clip.left; @@ -595,10 +593,8 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, sp sna GLuint previousFbo) { layer->setFbo(mCaches.fboCache.get()); -#if RENDER_LAYERS_AS_REGIONS snapshot->region = &snapshot->layer->region; snapshot->flags |= Snapshot::kFlagFboTarget; -#endif Rect clip(bounds); snapshot->transform->mapRect(clip); @@ -826,7 +822,6 @@ void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) } void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { -#if RENDER_LAYERS_AS_REGIONS if (layer->region.isRect()) { layer->setRegionAsRect(); @@ -907,9 +902,6 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { layer->region.clear(); } -#else - composeLayerRect(layer, rect); -#endif } void OpenGLRenderer::drawRegionRects(const Region& region) { @@ -940,27 +932,22 @@ void OpenGLRenderer::drawRegionRects(const Region& region) { void OpenGLRenderer::dirtyLayer(const float left, const float top, const float right, const float bottom, const mat4 transform) { -#if RENDER_LAYERS_AS_REGIONS if (hasLayer()) { Rect bounds(left, top, right, bottom); transform.mapRect(bounds); dirtyLayerUnchecked(bounds, getRegion()); } -#endif } void OpenGLRenderer::dirtyLayer(const float left, const float top, const float right, const float bottom) { -#if RENDER_LAYERS_AS_REGIONS if (hasLayer()) { Rect bounds(left, top, right, bottom); dirtyLayerUnchecked(bounds, getRegion()); } -#endif } void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) { -#if RENDER_LAYERS_AS_REGIONS if (bounds.intersect(*mSnapshot->clipRect)) { bounds.snapToPixelBoundaries(); android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom); @@ -968,7 +955,6 @@ void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) { region->orSelf(dirty); } } -#endif } void OpenGLRenderer::clearLayerRegions() { @@ -1585,11 +1571,7 @@ status_t OpenGLRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int mes float right = FLT_MIN; float bottom = FLT_MIN; -#if RENDER_LAYERS_AS_REGIONS const bool hasActiveLayer = hasLayer(); -#else - const bool hasActiveLayer = false; -#endif // TODO: Support the colors array TextureVertex mesh[count]; @@ -1620,7 +1602,6 @@ status_t OpenGLRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int mes TextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1); TextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2); -#if RENDER_LAYERS_AS_REGIONS if (hasActiveLayer) { // TODO: This could be optimized to avoid unnecessary ops left = fminf(left, fminf(vertices[ax], fminf(vertices[bx], vertices[cx]))); @@ -1628,15 +1609,12 @@ status_t OpenGLRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int mes right = fmaxf(right, fmaxf(vertices[ax], fmaxf(vertices[bx], vertices[cx]))); bottom = fmaxf(bottom, fmaxf(vertices[ay], fmaxf(vertices[by], vertices[cy]))); } -#endif } } -#if RENDER_LAYERS_AS_REGIONS if (hasActiveLayer) { dirtyLayer(left, top, right, bottom, *mSnapshot->transform); } -#endif drawTextureMesh(0.0f, 0.0f, 1.0f, 1.0f, texture->id, alpha / 255.0f, mode, texture->blend, &mesh[0].position[0], &mesh[0].texture[0], @@ -1734,7 +1712,6 @@ status_t OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const if (CC_LIKELY(mesh && mesh->verticesCount > 0)) { const bool pureTranslate = mSnapshot->transform->isPureTranslate(); -#if RENDER_LAYERS_AS_REGIONS // Mark the current layer dirty where we are going to draw the patch if (hasLayer() && mesh->hasEmptyQuads) { const float offsetX = left + mSnapshot->transform->getTranslateX(); @@ -1752,7 +1729,6 @@ status_t OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const } } } -#endif if (CC_LIKELY(pureTranslate)) { const float x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f); @@ -2400,22 +2376,16 @@ status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count const Rect* clip = pureTranslate ? mSnapshot->clipRect : &mSnapshot->getLocalClip(); Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); -#if RENDER_LAYERS_AS_REGIONS const bool hasActiveLayer = hasLayer(); -#else - const bool hasActiveLayer = false; -#endif if (fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y, positions, hasActiveLayer ? &bounds : NULL)) { -#if RENDER_LAYERS_AS_REGIONS if (hasActiveLayer) { if (!pureTranslate) { mSnapshot->transform->mapRect(bounds); } dirtyLayerUnchecked(bounds, getRegion()); } -#endif } return DrawGlInfo::kStatusDrew; @@ -2501,11 +2471,7 @@ status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, const Rect* clip = pureTranslate ? mSnapshot->clipRect : &mSnapshot->getLocalClip(); Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); -#if RENDER_LAYERS_AS_REGIONS const bool hasActiveLayer = hasLayer(); -#else - const bool hasActiveLayer = false; -#endif bool status; if (paint->getTextAlign() != SkPaint::kLeft_Align) { @@ -2517,15 +2483,12 @@ status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, status = fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y, positions, hasActiveLayer ? &bounds : NULL); } - if (status) { -#if RENDER_LAYERS_AS_REGIONS - if (hasActiveLayer) { - if (!pureTranslate) { - mSnapshot->transform->mapRect(bounds); - } - dirtyLayerUnchecked(bounds, getRegion()); + + if (status && hasActiveLayer) { + if (!pureTranslate) { + mSnapshot->transform->mapRect(bounds); } -#endif + dirtyLayerUnchecked(bounds, getRegion()); } drawTextDecorations(text, bytesCount, length, oldX, oldY, paint); @@ -2568,20 +2531,14 @@ status_t OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int co const Rect* clip = &mSnapshot->getLocalClip(); Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); -#if RENDER_LAYERS_AS_REGIONS const bool hasActiveLayer = hasLayer(); -#else - const bool hasActiveLayer = false; -#endif if (fontRenderer.renderTextOnPath(paint, clip, text, 0, bytesCount, count, path, hOffset, vOffset, hasActiveLayer ? &bounds : NULL)) { -#if RENDER_LAYERS_AS_REGIONS if (hasActiveLayer) { mSnapshot->transform->mapRect(bounds); dirtyLayerUnchecked(bounds, getRegion()); } -#endif } return DrawGlInfo::kStatusDrew; @@ -2610,6 +2567,8 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* pain return DrawGlInfo::kStatusDone; } + bool debugLayerUpdate = false; + if (layer->deferredUpdateScheduled && layer->renderer && layer->displayList) { OpenGLRenderer* renderer = layer->renderer; Rect& dirty = layer->dirtyRect; @@ -2625,6 +2584,8 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* pain layer->deferredUpdateScheduled = false; layer->renderer = NULL; layer->displayList = NULL; + + debugLayerUpdate = mCaches.debugLayersUpdates; } mCaches.activeTexture(0); @@ -2635,13 +2596,11 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* pain layer->setAlpha(alpha, mode); -#if RENDER_LAYERS_AS_REGIONS if (CC_LIKELY(!layer->region.isEmpty())) { if (layer->region.isRect()) { composeLayerRect(layer, layer->regionRect); } else if (layer->mesh) { const float a = alpha / 255.0f; - const Rect& rect = layer->layer; setupDraw(); setupDrawWithTexture(); @@ -2653,12 +2612,12 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* pain setupDrawColorFilterUniforms(); setupDrawTexture(layer->getTexture()); if (CC_LIKELY(mSnapshot->transform->isPureTranslate())) { - x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f); - y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f); + int tx = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f); + int ty = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f); layer->setFilter(GL_NEAREST); - setupDrawModelViewTranslate(x, y, - x + layer->layer.getWidth(), y + layer->layer.getHeight(), true); + setupDrawModelViewTranslate(tx, ty, + tx + layer->layer.getWidth(), ty + layer->layer.getHeight(), true); } else { layer->setFilter(GL_LINEAR); setupDrawModelViewTranslate(x, y, @@ -2675,11 +2634,12 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* pain drawRegionRects(layer->region); #endif } + + if (debugLayerUpdate) { + drawColorRect(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(), + 0x7f00ff00, SkXfermode::kSrcOver_Mode); + } } -#else - const Rect r(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight()); - composeLayerRect(layer, r); -#endif return DrawGlInfo::kStatusDrew; } diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp index 27f530c48fa64..6971d8a25314e 100644 --- a/libs/hwui/Patch.cpp +++ b/libs/hwui/Patch.cpp @@ -108,9 +108,7 @@ bool Patch::matches(const int32_t* xDivs, const int32_t* yDivs, const uint32_t c void Patch::updateVertices(const float bitmapWidth, const float bitmapHeight, float left, float top, float right, float bottom) { -#if RENDER_LAYERS_AS_REGIONS if (hasEmptyQuads) quads.clear(); -#endif // Reset the vertices count here, we will count exactly how many // vertices we actually need when generating the quads @@ -278,13 +276,11 @@ void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, f return; } -#if RENDER_LAYERS_AS_REGIONS // Record all non empty quads if (hasEmptyQuads) { Rect bounds(x1, y1, x2, y2); quads.add(bounds); } -#endif // Left triangle TextureVertex::set(vertex++, x1, y1, u1, v1); diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 3f3b39a1c3499..6b6dc9e73a141 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -25,9 +25,6 @@ * the OpenGLRenderer. */ -// If turned on, layers drawn inside FBOs are optimized with regions -#define RENDER_LAYERS_AS_REGIONS 1 - // If turned on, text is interpreted as glyphs instead of UTF-16 #define RENDER_TEXT_AS_GLYPHS 1 @@ -43,9 +40,10 @@ #define STENCIL_BUFFER_SIZE 0 /** - * Debug level for app developers. + * Debug level for app developers. The value is a numeric value defined + * by the DebugLevel enum below. */ -#define PROPERTY_DEBUG "hwui.debug_level" +#define PROPERTY_DEBUG "debug.hwui.level" /** * Debug levels. Debug levels are used as flags. @@ -57,6 +55,12 @@ enum DebugLevel { kDebugMoreCaches = kDebugMemory | kDebugCaches }; +/** + * Used to enable/disbale layers update debugging. The accepted values are + * "true" and "false". The default value is "false". + */ +#define PROPERTY_DEBUG_LAYERS_UPDATES "debug.hwui.show_layers_updates" + // These properties are defined in mega-bytes #define PROPERTY_TEXTURE_CACHE_SIZE "ro.hwui.texture_cache_size" #define PROPERTY_LAYER_CACHE_SIZE "ro.hwui.layer_cache_size"