Reduce the number of GL commands generated by the UI
This optimization along with the previous one lets us render an
application like Gmail using only 30% of the number of GL commands
previously required
Change-Id: Ifee63edaf495e04490b5abd5433bb9a07bc327a8
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 4da576d..27039dd 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -73,9 +73,12 @@
glBufferData(GL_ARRAY_BUFFER, sizeof(gMeshVertices), gMeshVertices, GL_STATIC_DRAW);
mCurrentBuffer = meshBuffer;
+ mCurrentIndicesBuffer = 0;
mCurrentPositionPointer = this;
mCurrentTexCoordsPointer = this;
+ mTexCoordsArrayEnabled = false;
+
mRegionMesh = NULL;
blend = false;
@@ -243,6 +246,24 @@
return false;
}
+bool Caches::bindIndicesBuffer(const GLuint buffer) {
+ if (mCurrentIndicesBuffer != buffer) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
+ mCurrentIndicesBuffer = buffer;
+ return true;
+ }
+ return false;
+}
+
+bool Caches::unbindIndicesBuffer() {
+ if (mCurrentIndicesBuffer) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ mCurrentIndicesBuffer = 0;
+ return true;
+ }
+ return false;
+}
+
void Caches::bindPositionVertexPointer(bool force, GLuint slot, GLvoid* vertices, GLsizei stride) {
if (force || vertices != mCurrentPositionPointer) {
glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
@@ -266,6 +287,20 @@
mCurrentTexCoordsPointer = this;
}
+void Caches::enableTexCoordsVertexArray() {
+ if (!mTexCoordsArrayEnabled) {
+ glEnableVertexAttribArray(Program::kBindingTexCoords);
+ mTexCoordsArrayEnabled = true;
+ }
+}
+
+void Caches::disbaleTexCoordsVertexArray() {
+ if (mTexCoordsArrayEnabled) {
+ glDisableVertexAttribArray(Program::kBindingTexCoords);
+ mTexCoordsArrayEnabled = false;
+ }
+}
+
TextureVertex* Caches::getRegionMesh() {
// Create the mesh, 2 triangles and 4 vertices per rectangle in the region
if (!mRegionMesh) {
@@ -284,13 +319,13 @@
}
glGenBuffers(1, &mRegionMeshIndices);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mRegionMeshIndices);
+ bindIndicesBuffer(mRegionMeshIndices);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, REGION_MESH_QUAD_COUNT * 6 * sizeof(uint16_t),
regionIndices, GL_STATIC_DRAW);
delete[] regionIndices;
} else {
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mRegionMeshIndices);
+ bindIndicesBuffer(mRegionMeshIndices);
}
return mRegionMesh;
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 7ca198a..6143593 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -150,6 +150,9 @@
*/
bool unbindMeshBuffer();
+ bool bindIndicesBuffer(const GLuint buffer);
+ bool unbindIndicesBuffer();
+
/**
* Binds an attrib to the specified float vertex pointer.
* Assumes a stride of gMeshStride and a size of 2.
@@ -169,6 +172,9 @@
void resetVertexPointers();
void resetTexCoordsVertexPointer();
+ void enableTexCoordsVertexArray();
+ void disbaleTexCoordsVertexArray();
+
/**
* Returns the mesh used to draw regions. Calling this method will
* bind a VBO of type GL_ELEMENT_ARRAY_BUFFER that contains the
@@ -214,9 +220,12 @@
private:
GLuint mCurrentBuffer;
+ GLuint mCurrentIndicesBuffer;
void* mCurrentPositionPointer;
void* mCurrentTexCoordsPointer;
+ bool mTexCoordsArrayEnabled;
+
// Used to render layers
TextureVertex* mRegionMesh;
GLuint mRegionMeshIndices;
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index f04ea6f..102aea6 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -22,6 +22,7 @@
#include <utils/Log.h>
+#include "Caches.h"
#include "Debug.h"
#include "FontRenderer.h"
@@ -536,9 +537,8 @@
}
glGenBuffers(1, &mIndexBufferID);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBufferID);
+ Caches::getInstance().bindIndicesBuffer(mIndexBufferID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSizeBytes, indexBufferData, GL_STATIC_DRAW);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
free(indexBufferData);
@@ -597,7 +597,18 @@
void FontRenderer::issueDrawCommand() {
checkTextureUpdate();
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBufferID);
+ Caches& caches = Caches::getInstance();
+ if (!mDrawn) {
+ float* buffer = mTextMeshPtr;
+ int offset = 2;
+
+ bool force = caches.unbindMeshBuffer();
+ caches.bindPositionVertexPointer(force, caches.currentProgram->position, buffer);
+ caches.bindTexCoordsVertexPointer(force, caches.currentProgram->texCoords,
+ buffer + offset);
+ }
+
+ caches.bindIndicesBuffer(mIndexBufferID);
glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, NULL);
mDrawn = true;
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index f945873..2a5a788 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -178,15 +178,6 @@
mGammaTable = gammaTable;
}
- inline float* getMeshBuffer() {
- checkInit();
- return mTextMeshPtr;
- }
-
- inline int getMeshTexCoordsOffset() const {
- return 2;
- }
-
void setFont(SkPaint* paint, uint32_t fontId, float fontSize);
bool renderText(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex,
uint32_t len, int numGlyphs, int x, int y, Rect* bounds);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index fcac053..59d3fcc 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -144,6 +144,7 @@
glDisable(GL_DITHER);
glEnable(GL_SCISSOR_TEST);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+
glEnableVertexAttribArray(Program::kBindingPosition);
}
@@ -199,7 +200,9 @@
}
}
mCaches.unbindMeshBuffer();
+ mCaches.unbindIndicesBuffer();
mCaches.resetVertexPointers();
+ mCaches.disbaleTexCoordsVertexArray();
}
void OpenGLRenderer::resume() {
@@ -212,7 +215,6 @@
dirtyClip();
glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
mCaches.blend = true;
glEnable(GL_BLEND);
@@ -771,7 +773,7 @@
layer->setFilter(GL_LINEAR);
setupDrawModelViewTranslate(rect.left, rect.top, rect.right, rect.bottom);
}
- setupDrawMesh(&mesh[0].position[0], &mesh[0].texture[0]);
+ setupDrawMeshIndices(&mesh[0].position[0], &mesh[0].texture[0]);
for (size_t i = 0; i < count; i++) {
const android::Rect* r = &rects[i];
@@ -800,7 +802,6 @@
glDrawElements(GL_TRIANGLES, numQuads * 6, GL_UNSIGNED_SHORT, NULL);
}
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
finishDrawTexture();
#if DEBUG_LAYERS_AS_REGIONS
@@ -1015,7 +1016,6 @@
mColorA = mColorR = mColorG = mColorB = 0.0f;
mTextureUnit = 0;
mTrackDirtyRegions = true;
- mTexCoordsSlot = -1;
}
void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) {
@@ -1027,6 +1027,10 @@
mDescription.hasExternalTexture = true;
}
+void OpenGLRenderer::setupDrawNoTexture() {
+ mCaches.disbaleTexCoordsVertexArray();
+}
+
void OpenGLRenderer::setupDrawAALine() {
mDescription.isAA = true;
}
@@ -1203,22 +1207,19 @@
void OpenGLRenderer::setupDrawSimpleMesh() {
bool force = mCaches.bindMeshBuffer();
mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position, 0);
+ mCaches.unbindIndicesBuffer();
}
void OpenGLRenderer::setupDrawTexture(GLuint texture) {
bindTexture(texture);
glUniform1i(mCaches.currentProgram->getUniform("sampler"), mTextureUnit++);
-
- mTexCoordsSlot = mCaches.currentProgram->texCoords;
- glEnableVertexAttribArray(mTexCoordsSlot);
+ mCaches.enableTexCoordsVertexArray();
}
void OpenGLRenderer::setupDrawExternalTexture(GLuint texture) {
bindExternalTexture(texture);
glUniform1i(mCaches.currentProgram->getUniform("sampler"), mTextureUnit++);
-
- mTexCoordsSlot = mCaches.currentProgram->texCoords;
- glEnableVertexAttribArray(mTexCoordsSlot);
+ mCaches.enableTexCoordsVertexArray();
}
void OpenGLRenderer::setupDrawTextureTransform() {
@@ -1239,8 +1240,18 @@
}
mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position, vertices);
- if (mTexCoordsSlot >= 0) {
- mCaches.bindTexCoordsVertexPointer(force, mTexCoordsSlot, texCoords);
+ if (mCaches.currentProgram->texCoords >= 0) {
+ mCaches.bindTexCoordsVertexPointer(force, mCaches.currentProgram->texCoords, texCoords);
+ }
+
+ mCaches.unbindIndicesBuffer();
+}
+
+void OpenGLRenderer::setupDrawMeshIndices(GLvoid* vertices, GLvoid* texCoords) {
+ bool force = mCaches.unbindMeshBuffer();
+ mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position, vertices);
+ if (mCaches.currentProgram->texCoords >= 0) {
+ mCaches.bindTexCoordsVertexPointer(force, mCaches.currentProgram->texCoords, texCoords);
}
}
@@ -1248,6 +1259,7 @@
bool force = mCaches.unbindMeshBuffer();
mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position,
vertices, gVertexStride);
+ mCaches.unbindIndicesBuffer();
}
/**
@@ -1267,6 +1279,7 @@
mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position,
vertices, gAAVertexStride);
mCaches.resetTexCoordsVertexPointer();
+ mCaches.unbindIndicesBuffer();
int widthSlot = mCaches.currentProgram->getAttrib("vtxWidth");
glEnableVertexAttribArray(widthSlot);
@@ -1285,7 +1298,6 @@
}
void OpenGLRenderer::finishDrawTexture() {
- glDisableVertexAttribArray(mTexCoordsSlot);
}
///////////////////////////////////////////////////////////////////////////////
@@ -1624,6 +1636,7 @@
}
setupDraw();
+ setupDrawNoTexture();
setupDrawAALine();
setupDrawColor(color);
setupDrawColorFilter();
@@ -1734,6 +1747,7 @@
getAlphaAndMode(paint, &alpha, &mode);
setupDraw();
+ setupDrawNoTexture();
if (isAA) {
setupDrawAALine();
}
@@ -1943,6 +1957,7 @@
TextureVertex* vertex = &pointsData[0];
setupDraw();
+ setupDrawNoTexture();
setupDrawPoint(strokeWidth);
setupDrawColor(paint->getColor(), alpha);
setupDrawColorFilter();
@@ -2186,13 +2201,6 @@
bool hasActiveLayer = false;
#endif
- float* buffer = fontRenderer.getMeshBuffer();
- int offset = fontRenderer.getMeshTexCoordsOffset();
-
- bool force = mCaches.unbindMeshBuffer();
- mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position, buffer);
- mCaches.bindTexCoordsVertexPointer(force, mTexCoordsSlot, buffer + offset);
-
if (fontRenderer.renderText(paint, clip, text, 0, bytesCount, count, x, y,
hasActiveLayer ? &bounds : NULL)) {
#if RENDER_LAYERS_AS_REGIONS
@@ -2205,9 +2213,6 @@
#endif
}
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- glDisableVertexAttribArray(mCaches.currentProgram->texCoords);
-
drawTextDecorations(text, bytesCount, length, oldX, oldY, paint);
}
@@ -2437,6 +2442,7 @@
}
setupDraw();
+ setupDrawNoTexture();
setupDrawColor(color);
setupDrawShader();
setupDrawColorFilter();
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index cd9ff93..019e9b2 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -498,6 +498,7 @@
*/
void setupDrawWithTexture(bool isAlpha8 = false);
void setupDrawWithExternalTexture();
+ void setupDrawNoTexture();
void setupDrawAALine();
void setupDrawPoint(float pointSize);
void setupDrawColor(int color);
@@ -530,6 +531,7 @@
void setupDrawTextureTransform();
void setupDrawTextureTransformUniforms(mat4& transform);
void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords = NULL, GLuint vbo = 0);
+ void setupDrawMeshIndices(GLvoid* vertices, GLvoid* texCoords);
void setupDrawVertices(GLvoid* vertices);
void setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, GLvoid* lengthCoords,
float strokeWidth);
@@ -601,8 +603,6 @@
GLuint mTextureUnit;
// Track dirty regions, true by default
bool mTrackDirtyRegions;
- // Texture coordinates slot
- int mTexCoordsSlot;
friend class DisplayListRenderer;