Merge "Add new debug tool to track hardware layers updates" into jb-mr1-dev
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -881,15 +881,17 @@ public final class Bitmap implements Parcelable {
|
||||
* <code>(128, 128, 0, 0)</code>.</p>
|
||||
*
|
||||
* <p>This method always returns false if {@link #getConfig()} is
|
||||
* {@link Bitmap.Config#ALPHA_8} or {@link Bitmap.Config#RGB_565}.</p>
|
||||
* {@link Bitmap.Config#RGB_565}.</p>
|
||||
*
|
||||
* <p>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.</p>
|
||||
*
|
||||
* @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 */
|
||||
|
||||
@@ -52,13 +52,10 @@ Caches::Caches(): Singleton<Caches>(), 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;
|
||||
|
||||
|
||||
@@ -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) { }
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -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<Snapshot> 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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user