Update 9patch structure when rendering with different divs/colors.
Bug #3221488
Change-Id: Ifc9e42a991d630feadc9e8032322f37504d09d6d
diff --git a/libs/hwui/Line.h b/libs/hwui/Line.h
index 5c6f3d8..264fd19 100644
--- a/libs/hwui/Line.h
+++ b/libs/hwui/Line.h
@@ -58,6 +58,8 @@
mXDivs[0] = mYDivs[0] = 2;
mXDivs[1] = mYDivs[1] = 3;
+ mPatch->copy(mXDivs, mYDivs);
+
glGenTextures(1, &mTexture);
glBindTexture(GL_TEXTURE_2D, mTexture);
@@ -89,8 +91,7 @@
const float half = lineWidth * 0.5f;
mPatch->updateVertices(gLineTextureWidth, gLineTextureHeight,
- -gLineAABias, -half - gLineAABias, length + gLineAABias, half + gLineAABias,
- mXDivs, mYDivs, mXDivsCount, mYDivsCount);
+ -gLineAABias, -half - gLineAABias, length + gLineAABias, half + gLineAABias);
tx = -gLineAABias;
ty = lineWidth <= 1.0f ? -gLineAABias : -half - gLineAABias;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index ad72584..60343e0 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -952,6 +952,9 @@
mode, texture->blend, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset,
GL_TRIANGLES, mesh->verticesCount, false, false, mesh->meshBuffer,
true, !mesh->hasEmptyQuads);
+ } else {
+ PATCH_LOGD("Invisible 9patch, ignoring (%.2f, %.2f, %.2f, %.2f)",
+ left, top, right, bottom);
}
}
diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp
index 9b2d476..7ca289d 100644
--- a/libs/hwui/Patch.cpp
+++ b/libs/hwui/Patch.cpp
@@ -30,32 +30,81 @@
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
-Patch::Patch(const uint32_t xCount, const uint32_t yCount, const int8_t emptyQuads) {
+Patch::Patch(const uint32_t xCount, const uint32_t yCount, const int8_t emptyQuads):
+ mXCount(xCount), mYCount(yCount) {
// 2 triangles per patch, 3 vertices per triangle
verticesCount = ((xCount + 1) * (yCount + 1) - emptyQuads) * 2 * 3;
mVertices = new TextureVertex[verticesCount];
hasEmptyQuads = emptyQuads > 0;
+ mUploaded = false;
+
+ mColorKey = 0;
+ mXDivs = new int32_t[mXCount];
+ mYDivs = new int32_t[mYCount];
glGenBuffers(1, &meshBuffer);
}
Patch::~Patch() {
delete[] mVertices;
+ delete[] mXDivs;
+ delete[] mYDivs;
glDeleteBuffers(1, &meshBuffer);
}
///////////////////////////////////////////////////////////////////////////////
+// Patch management
+///////////////////////////////////////////////////////////////////////////////
+
+void Patch::copy(const int32_t* xDivs, const int32_t* yDivs) {
+ memcpy(mXDivs, xDivs, mXCount * sizeof(int32_t));
+ memcpy(mYDivs, yDivs, mYCount * sizeof(int32_t));
+}
+
+void Patch::copy(const int32_t* yDivs) {
+ memcpy(mYDivs, yDivs, mYCount * sizeof(int32_t));
+}
+
+void Patch::updateColorKey(const uint32_t colorKey) {
+ mColorKey = colorKey;
+}
+
+bool Patch::matches(const int32_t* xDivs, const int32_t* yDivs, const uint32_t colorKey) {
+ if (mColorKey != colorKey) {
+ updateColorKey(colorKey);
+ copy(xDivs, yDivs);
+ return false;
+ }
+
+ for (uint32_t i = 0; i < mXCount; i++) {
+ if (mXDivs[i] != xDivs[i]) {
+ // The Y divs may or may not match, copy everything
+ copy(xDivs, yDivs);
+ return false;
+ }
+ }
+
+ for (uint32_t i = 0; i < mYCount; i++) {
+ if (mYDivs[i] != yDivs[i]) {
+ // We know all the X divs match, copy only Y divs
+ copy(yDivs);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
// Vertices management
///////////////////////////////////////////////////////////////////////////////
void Patch::updateVertices(const float bitmapWidth, const float bitmapHeight,
- float left, float top, float right, float bottom,
- const int32_t* xDivs, const int32_t* yDivs,
- const uint32_t width, const uint32_t height, const uint32_t colorKey) {
+ float left, float top, float right, float bottom) {
if (hasEmptyQuads) quads.clear();
- const uint32_t xStretchCount = (width + 1) >> 1;
- const uint32_t yStretchCount = (height + 1) >> 1;
+ const uint32_t xStretchCount = (mXCount + 1) >> 1;
+ const uint32_t yStretchCount = (mYCount + 1) >> 1;
float stretchX = 0.0f;
float stretchY = 0.0;
@@ -64,8 +113,8 @@
if (xStretchCount > 0) {
uint32_t stretchSize = 0;
- for (uint32_t i = 1; i < width; i += 2) {
- stretchSize += xDivs[i] - xDivs[i - 1];
+ for (uint32_t i = 1; i < mXCount; i += 2) {
+ stretchSize += mXDivs[i] - mXDivs[i - 1];
}
const float xStretchTex = stretchSize;
const float fixed = bitmapWidth - stretchSize;
@@ -75,8 +124,8 @@
if (yStretchCount > 0) {
uint32_t stretchSize = 0;
- for (uint32_t i = 1; i < height; i += 2) {
- stretchSize += yDivs[i] - yDivs[i - 1];
+ for (uint32_t i = 1; i < mYCount; i += 2) {
+ stretchSize += mYDivs[i] - mYDivs[i - 1];
}
const float yStretchTex = stretchSize;
const float fixed = bitmapHeight - stretchSize;
@@ -92,8 +141,8 @@
float y1 = 0.0f;
float v1 = 0.0f;
- for (uint32_t i = 0; i < height; i++) {
- float stepY = yDivs[i];
+ for (uint32_t i = 0; i < mYCount; i++) {
+ float stepY = mYDivs[i];
float y2 = 0.0f;
if (i & 1) {
@@ -104,8 +153,7 @@
}
float v2 = fmax(0.0f, stepY - 0.5f) / bitmapHeight;
- generateRow(vertex, y1, y2, v1, v2, xDivs, width, stretchX,
- right - left, bitmapWidth, quadCount, colorKey);
+ generateRow(vertex, y1, y2, v1, v2, stretchX, right - left, bitmapWidth, quadCount);
y1 = y2;
v1 = (stepY + 0.5f) / bitmapHeight;
@@ -113,25 +161,30 @@
previousStepY = stepY;
}
- generateRow(vertex, y1, bottom - top, v1, 1.0f, xDivs, width, stretchX,
- right - left, bitmapWidth, quadCount, colorKey);
+ generateRow(vertex, y1, bottom - top, v1, 1.0f, stretchX, right - left,
+ bitmapWidth, quadCount);
Caches::getInstance().bindMeshBuffer(meshBuffer);
- glBufferData(GL_ARRAY_BUFFER, sizeof(TextureVertex) * verticesCount,
- mVertices, GL_STATIC_DRAW);
+ if (!mUploaded) {
+ glBufferData(GL_ARRAY_BUFFER, sizeof(TextureVertex) * verticesCount,
+ mVertices, GL_DYNAMIC_DRAW);
+ mUploaded = true;
+ } else {
+ glBufferSubData(GL_ARRAY_BUFFER, 0,
+ sizeof(TextureVertex) * verticesCount, mVertices);
+ }
}
void Patch::generateRow(TextureVertex*& vertex, float y1, float y2, float v1, float v2,
- const int32_t xDivs[], uint32_t xCount, float stretchX, float width, float bitmapWidth,
- uint32_t& quadCount, const uint32_t colorKey) {
+ float stretchX, float width, float bitmapWidth, uint32_t& quadCount) {
float previousStepX = 0.0f;
float x1 = 0.0f;
float u1 = 0.0f;
// Generate the row quad by quad
- for (uint32_t i = 0; i < xCount; i++) {
- float stepX = xDivs[i];
+ for (uint32_t i = 0; i < mXCount; i++) {
+ float stepX = mXDivs[i];
float x2 = 0.0f;
if (i & 1) {
@@ -142,7 +195,7 @@
}
float u2 = fmax(0.0f, stepX - 0.5f) / bitmapWidth;
- generateQuad(vertex, x1, y1, x2, y2, u1, v1, u2, v2, quadCount, colorKey);
+ generateQuad(vertex, x1, y1, x2, y2, u1, v1, u2, v2, quadCount);
x1 = x2;
u1 = (stepX + 0.5f) / bitmapWidth;
@@ -150,12 +203,12 @@
previousStepX = stepX;
}
- generateQuad(vertex, x1, y1, width, y2, u1, v1, 1.0f, v2, quadCount, colorKey);
+ generateQuad(vertex, x1, y1, width, y2, u1, v1, 1.0f, v2, quadCount);
}
void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
- float u1, float v1, float u2, float v2, uint32_t& quadCount, const uint32_t colorKey) {
- if (((colorKey >> quadCount++) & 0x1) == 1) {
+ float u1, float v1, float u2, float v2, uint32_t& quadCount) {
+ if (((mColorKey >> quadCount++) & 0x1) == 1) {
return;
}
diff --git a/libs/hwui/Patch.h b/libs/hwui/Patch.h
index 1e78b2f..2cb8ecb 100644
--- a/libs/hwui/Patch.h
+++ b/libs/hwui/Patch.h
@@ -35,55 +35,6 @@
///////////////////////////////////////////////////////////////////////////////
/**
- * Description of a patch.
- */
-struct PatchDescription {
- PatchDescription(): bitmapWidth(0), bitmapHeight(0), pixelWidth(0), pixelHeight(0),
- xCount(0), yCount(0), emptyCount(0), colorKey(0) { }
- PatchDescription(const float bitmapWidth, const float bitmapHeight,
- const float pixelWidth, const float pixelHeight,
- const uint32_t xCount, const uint32_t yCount,
- const int8_t emptyCount, const uint32_t colorKey):
- bitmapWidth(bitmapWidth), bitmapHeight(bitmapHeight),
- pixelWidth(pixelWidth), pixelHeight(pixelHeight),
- xCount(xCount), yCount(yCount),
- emptyCount(emptyCount), colorKey(colorKey) { }
- PatchDescription(const PatchDescription& description):
- bitmapWidth(description.bitmapWidth), bitmapHeight(description.bitmapHeight),
- pixelWidth(description.pixelWidth), pixelHeight(description.pixelHeight),
- xCount(description.xCount), yCount(description.yCount),
- emptyCount(description.emptyCount), colorKey(description.colorKey) { }
-
- float bitmapWidth;
- float bitmapHeight;
- float pixelWidth;
- float pixelHeight;
- uint32_t xCount;
- uint32_t yCount;
- int8_t emptyCount;
- uint32_t colorKey;
-
- bool operator<(const PatchDescription& rhs) const {
- LTE_FLOAT(bitmapWidth) {
- LTE_FLOAT(bitmapHeight) {
- LTE_FLOAT(pixelWidth) {
- LTE_FLOAT(pixelHeight) {
- LTE_INT(xCount) {
- LTE_INT(yCount) {
- LTE_INT(emptyCount) {
- LTE_INT(colorKey) return false;
- }
- }
- }
- }
- }
- }
- }
- return false;
- }
-}; // struct PatchDescription
-
-/**
* An OpenGL patch. This contains an array of vertices and an array of
* indices to render the vertices.
*/
@@ -92,10 +43,11 @@
~Patch();
void updateVertices(const float bitmapWidth, const float bitmapHeight,
- float left, float top, float right, float bottom,
- const int32_t* xDivs, const int32_t* yDivs,
- const uint32_t width, const uint32_t height,
- const uint32_t colorKey = 0);
+ float left, float top, float right, float bottom);
+
+ void updateColorKey(const uint32_t colorKey);
+ void copy(const int32_t* xDivs, const int32_t* yDivs);
+ bool matches(const int32_t* xDivs, const int32_t* yDivs, const uint32_t colorKey);
GLuint meshBuffer;
uint32_t verticesCount;
@@ -104,15 +56,23 @@
private:
TextureVertex* mVertices;
+ bool mUploaded;
+
+ uint32_t mXCount;
+ int32_t* mXDivs;
+ uint32_t mYCount;
+ int32_t* mYDivs;
+ uint32_t mColorKey;
+
+ void copy(const int32_t* yDivs);
void generateRow(TextureVertex*& vertex, float y1, float y2,
- float v1, float v2, const int32_t xDivs[], uint32_t xCount,
- float stretchX, float width, float bitmapWidth,
- uint32_t& quadCount, const uint32_t colorKey);
+ float v1, float v2, float stretchX, float width, float bitmapWidth,
+ uint32_t& quadCount);
void generateQuad(TextureVertex*& vertex,
float x1, float y1, float x2, float y2,
float u1, float v1, float u2, float v2,
- uint32_t& quadCount, const uint32_t colorKey);
+ uint32_t& quadCount);
}; // struct Patch
}; // namespace uirenderer
diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp
index 71bab91..9702c3d 100644
--- a/libs/hwui/PatchCache.cpp
+++ b/libs/hwui/PatchCache.cpp
@@ -87,8 +87,9 @@
width, height, pixelWidth, pixelHeight, bitmapWidth, bitmapHeight);
mesh = new Patch(width, height, transparentQuads);
- mesh->updateVertices(bitmapWidth, bitmapHeight, 0.0f, 0.0f,
- pixelWidth, pixelHeight, xDivs, yDivs, width, height, colorKey);
+ mesh->updateColorKey(colorKey);
+ mesh->copy(xDivs, yDivs);
+ mesh->updateVertices(bitmapWidth, bitmapHeight, 0.0f, 0.0f, pixelWidth, pixelHeight);
if (mCache.size() >= mMaxEntries) {
delete mCache.valueAt(mCache.size() - 1);
@@ -96,6 +97,9 @@
}
mCache.add(description, mesh);
+ } else if (!mesh->matches(xDivs, yDivs, colorKey)) {
+ PATCH_LOGD("Patch mesh does not match, refreshing vertices");
+ mesh->updateVertices(bitmapWidth, bitmapHeight, 0.0f, 0.0f, pixelWidth, pixelHeight);
}
return mesh;
diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h
index c38cd99..951fba3 100644
--- a/libs/hwui/PatchCache.h
+++ b/libs/hwui/PatchCache.h
@@ -61,8 +61,65 @@
}
private:
+ /**
+ * Description of a patch.
+ */
+ struct PatchDescription {
+ PatchDescription(): bitmapWidth(0), bitmapHeight(0), pixelWidth(0), pixelHeight(0),
+ xCount(0), yCount(0), emptyCount(0), colorKey(0) {
+ }
+
+ PatchDescription(const float bitmapWidth, const float bitmapHeight,
+ const float pixelWidth, const float pixelHeight,
+ const uint32_t xCount, const uint32_t yCount,
+ const int8_t emptyCount, const uint32_t colorKey):
+ bitmapWidth(bitmapWidth), bitmapHeight(bitmapHeight),
+ pixelWidth(pixelWidth), pixelHeight(pixelHeight),
+ xCount(xCount), yCount(yCount),
+ emptyCount(emptyCount), colorKey(colorKey) {
+ }
+
+ PatchDescription(const PatchDescription& description):
+ bitmapWidth(description.bitmapWidth), bitmapHeight(description.bitmapHeight),
+ pixelWidth(description.pixelWidth), pixelHeight(description.pixelHeight),
+ xCount(description.xCount), yCount(description.yCount),
+ emptyCount(description.emptyCount), colorKey(description.colorKey) {
+ }
+
+ bool operator<(const PatchDescription& rhs) const {
+ LTE_FLOAT(bitmapWidth) {
+ LTE_FLOAT(bitmapHeight) {
+ LTE_FLOAT(pixelWidth) {
+ LTE_FLOAT(pixelHeight) {
+ LTE_INT(xCount) {
+ LTE_INT(yCount) {
+ LTE_INT(emptyCount) {
+ LTE_INT(colorKey) return false;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private:
+ float bitmapWidth;
+ float bitmapHeight;
+ float pixelWidth;
+ float pixelHeight;
+ uint32_t xCount;
+ uint32_t yCount;
+ int8_t emptyCount;
+ uint32_t colorKey;
+
+ }; // struct PatchDescription
+
uint32_t mMaxEntries;
KeyedVector<PatchDescription, Patch*> mCache;
+
}; // class PatchCache
}; // namespace uirenderer