Avoid 9patch cache lookups when possible
This optimization saves up to 0.3ms per frame on the Play Store's
front page, on a Nexus 4 device.
Change-Id: Iaa4ef33c6e3b37e175efd5b9eea9ef59b43f14f3
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 6839b18..028decd 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -932,13 +932,22 @@
DrawPatchOp(SkBitmap* bitmap, Res_png_9patch* patch,
float left, float top, float right, float bottom, int alpha, SkXfermode::Mode mode)
: DrawBoundedOp(left, top, right, bottom, 0),
- mBitmap(bitmap), mPatch(patch), mAlpha(alpha), mMode(mode) {
+ mBitmap(bitmap), mPatch(patch), mAlpha(alpha), mMode(mode),
+ mGenerationId(0), mMesh(NULL) {
mEntry = Caches::getInstance().assetAtlas.getEntry(bitmap);
};
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
- // NOTE: not calling the virtual method, which takes a paint
- return renderer.drawPatch(mBitmap, mPatch, mEntry, mLocalBounds.left, mLocalBounds.top,
+ if (!mMesh || renderer.getCaches().patchCache.getGenerationId() != mGenerationId) {
+ PatchCache& cache = renderer.getCaches().patchCache;
+ mMesh = cache.get(mEntry, mBitmap->width(), mBitmap->height(),
+ mLocalBounds.right - mLocalBounds.left, mLocalBounds.bottom - mLocalBounds.top,
+ mPatch);
+ mGenerationId = cache.getGenerationId();
+ }
+ // We're not calling the public variant of drawPatch() here
+ // This method won't perform the quickReject() since we've already done it at this point
+ return renderer.drawPatch(mBitmap, mMesh, mEntry, mLocalBounds.left, mLocalBounds.top,
mLocalBounds.right, mLocalBounds.bottom, mAlpha, mMode);
}
@@ -957,8 +966,12 @@
private:
SkBitmap* mBitmap;
Res_png_9patch* mPatch;
+
int mAlpha;
SkXfermode::Mode mMode;
+
+ uint32_t mGenerationId;
+ const Patch* mMesh;
AssetAtlas::Entry* mEntry;
};
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 79e0b0c..cfb1e97e 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -467,7 +467,7 @@
mat4 texTransform(layer->getTexTransform());
mat4 invert;
- invert.translate(0.0f, 1.0f, 0.0f);
+ invert.translate(0.0f, 1.0f);
invert.scale(1.0f, -1.0f, 1.0f);
layer->getTexTransform().multiply(invert);
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index 75e280c..df744be 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -128,10 +128,27 @@
void multiply(float v);
- void translate(float x, float y, float z) {
- Matrix4 u;
- u.loadTranslate(x, y, z);
- multiply(u);
+ void translate(float x, float y) {
+ if ((getType() & sGeometryMask) == kTypeTranslate) {
+ data[kTranslateX] += x;
+ data[kTranslateY] += y;
+ } else {
+ // Doing a translation will only affect the translate bit of the type
+ // Save the type
+ uint32_t type = mType;
+
+ Matrix4 u;
+ u.loadTranslate(x, y, 0.0f);
+ multiply(u);
+
+ // Restore the type and fix the translate bit
+ mType = type;
+ if (data[kTranslateX] != 0.0f || data[kTranslateY] != 0.0f) {
+ mType |= kTypeTranslate;
+ } else {
+ mType &= ~kTypeTranslate;
+ }
+ }
}
void scale(float sx, float sy, float sz) {
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index f5343b1..d95a62c 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1407,7 +1407,7 @@
///////////////////////////////////////////////////////////////////////////////
void OpenGLRenderer::translate(float dx, float dy) {
- currentTransform().translate(dx, dy, 0.0f);
+ currentTransform().translate(dx, dy);
}
void OpenGLRenderer::rotate(float degrees) {
@@ -2337,20 +2337,25 @@
SkXfermode::Mode mode;
getAlphaAndMode(paint, &alpha, &mode);
- return drawPatch(bitmap, patch, mCaches.assetAtlas.getEntry(bitmap),
- left, top, right, bottom, alpha, mode);
-}
-
-status_t OpenGLRenderer::drawPatch(SkBitmap* bitmap, Res_png_9patch* patch,
- AssetAtlas::Entry* entry, float left, float top, float right, float bottom,
- int alpha, SkXfermode::Mode mode) {
if (quickReject(left, top, right, bottom)) {
return DrawGlInfo::kStatusDone;
}
+ AssetAtlas::Entry* entry = mCaches.assetAtlas.getEntry(bitmap);
const Patch* mesh = mCaches.patchCache.get(entry, bitmap->width(), bitmap->height(),
right - left, bottom - top, patch);
+ return drawPatch(bitmap, mesh, entry, left, top, right, bottom, alpha, mode);
+}
+
+status_t OpenGLRenderer::drawPatch(SkBitmap* bitmap, const Patch* mesh,
+ AssetAtlas::Entry* entry, float left, float top, float right, float bottom,
+ int alpha, SkXfermode::Mode mode) {
+
+ if (quickReject(left, top, right, bottom)) {
+ return DrawGlInfo::kStatusDone;
+ }
+
if (CC_LIKELY(mesh && mesh->verticesCount > 0)) {
mCaches.activeTexture(0);
Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index e9ea2f32..ce4ce42 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -266,7 +266,7 @@
float* vertices, int* colors, SkPaint* paint);
virtual status_t drawPatch(SkBitmap* bitmap, Res_png_9patch* patch,
float left, float top, float right, float bottom, SkPaint* paint);
- status_t drawPatch(SkBitmap* bitmap, Res_png_9patch* patch, AssetAtlas::Entry* entry,
+ status_t drawPatch(SkBitmap* bitmap, const Patch* mesh, AssetAtlas::Entry* entry,
float left, float top, float right, float bottom, int alpha, SkXfermode::Mode mode);
virtual status_t drawColor(int color, SkXfermode::Mode mode);
virtual status_t drawRect(float left, float top, float right, float bottom, SkPaint* paint);
diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp
index c6ed275..c23e991 100644
--- a/libs/hwui/PatchCache.cpp
+++ b/libs/hwui/PatchCache.cpp
@@ -30,7 +30,9 @@
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
-PatchCache::PatchCache(): mCache(LruCache<PatchDescription, Patch*>::kUnlimitedCapacity) {
+PatchCache::PatchCache():
+ mSize(0), mCache(LruCache<PatchDescription, Patch*>::kUnlimitedCapacity),
+ mMeshBuffer(0), mGenerationId(0) {
char property[PROPERTY_VALUE_MAX];
if (property_get(PROPERTY_PATCH_CACHE_SIZE, property, NULL) > 0) {
INIT_LOGD(" Setting patch cache size to %skB", property);
@@ -39,8 +41,6 @@
INIT_LOGD(" Using default patch cache size of %.2fkB", DEFAULT_PATCH_CACHE_SIZE);
mMaxSize = KB(DEFAULT_PATCH_CACHE_SIZE);
}
- mSize = 0;
- mMeshBuffer = 0;
}
PatchCache::~PatchCache() {
@@ -58,7 +58,7 @@
caches.resetVertexPointers();
if (created) {
- glBufferData(GL_ARRAY_BUFFER, mMaxSize, NULL, GL_DYNAMIC_DRAW);
+ createVertexBuffer();
}
}
@@ -99,6 +99,12 @@
mCache.clear();
}
+void PatchCache::createVertexBuffer() {
+ glBufferData(GL_ARRAY_BUFFER, mMaxSize, NULL, GL_DYNAMIC_DRAW);
+ mSize = 0;
+ mGenerationId++;
+}
+
const Patch* PatchCache::get(const AssetAtlas::Entry* entry,
const uint32_t bitmapWidth, const uint32_t bitmapHeight,
const float pixelWidth, const float pixelHeight, const Res_png_9patch* patch) {
@@ -127,8 +133,7 @@
uint32_t size = newMesh->getSize();
if (mSize + size > mMaxSize) {
clearCache();
- glBufferData(GL_ARRAY_BUFFER, mMaxSize, NULL, GL_DYNAMIC_DRAW);
- mSize = 0;
+ createVertexBuffer();
}
newMesh->offset = (GLintptr) mSize;
diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h
index 530dad0..1829b89 100644
--- a/libs/hwui/PatchCache.h
+++ b/libs/hwui/PatchCache.h
@@ -70,8 +70,13 @@
return mMeshBuffer;
}
+ uint32_t getGenerationId() const {
+ return mGenerationId;
+ }
+
private:
void clearCache();
+ void createVertexBuffer();
struct PatchDescription {
PatchDescription(): mPatch(NULL), mBitmapWidth(0), mBitmapHeight(0),
@@ -122,9 +127,11 @@
uint32_t mMaxSize;
uint32_t mSize;
+ LruCache<PatchDescription, Patch*> mCache;
+
GLuint mMeshBuffer;
- LruCache<PatchDescription, Patch*> mCache;
+ uint32_t mGenerationId;
}; // class PatchCache
}; // namespace uirenderer
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index c127d68..9e4670e 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -172,7 +172,7 @@
// up and to the left.
// This offset value is based on an assumption that some hardware may use as
// little as 12.4 precision, so we offset by slightly more than 1/16.
- p.translate(.065, .065, 0);
+ p.translate(.065, .065);
glUniformMatrix4fv(projection, 1, GL_FALSE, &p.data[0]);
}
mProjection = projectionMatrix;