summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Romain Guy <romainguy@google.com> 2010-10-27 18:57:51 -0700
committer Romain Guy <romainguy@google.com> 2010-11-02 16:17:23 -0700
commit5b3b35296e8b2c8d3f07d32bb645d5414db41a1d (patch)
treebad2ebdbfeb8a3a0be1591d5a357a8280df7d1d2
parent2444ddb3d9b59ec45ba50858fcbff639e59b93b1 (diff)
Optimize FBO drawing with regions.
This optimization is currently disabled until Launcher is modified to take advantage of it. The optimization can be enabled by turning on RENDER_LAYERS_AS_REGIONS in the OpenGLRenderer.h file. Change-Id: I2fdf59d0f4dc690a3d7f712173ab8db3848b27b1
-rw-r--r--core/java/com/android/internal/widget/LockPatternView.java10
-rw-r--r--libs/hwui/Android.mk2
-rw-r--r--libs/hwui/Caches.cpp48
-rw-r--r--libs/hwui/Caches.h32
-rw-r--r--libs/hwui/DisplayListRenderer.cpp17
-rw-r--r--libs/hwui/DisplayListRenderer.h9
-rw-r--r--libs/hwui/Extensions.h6
-rw-r--r--libs/hwui/FboCache.h6
-rw-r--r--libs/hwui/FontRenderer.cpp20
-rw-r--r--libs/hwui/FontRenderer.h12
-rw-r--r--libs/hwui/GammaFontRenderer.h6
-rw-r--r--libs/hwui/GradientCache.h6
-rw-r--r--libs/hwui/Layer.h14
-rw-r--r--libs/hwui/LayerCache.h6
-rw-r--r--libs/hwui/Line.h6
-rw-r--r--libs/hwui/Matrix.cpp13
-rw-r--r--libs/hwui/Matrix.h6
-rw-r--r--libs/hwui/OpenGLDebugRenderer.h6
-rw-r--r--libs/hwui/OpenGLRenderer.cpp405
-rw-r--r--libs/hwui/OpenGLRenderer.h57
-rw-r--r--libs/hwui/Patch.cpp12
-rw-r--r--libs/hwui/Patch.h15
-rw-r--r--libs/hwui/PatchCache.h6
-rw-r--r--libs/hwui/PathCache.h6
-rw-r--r--libs/hwui/Program.cpp6
-rw-r--r--libs/hwui/Program.h6
-rw-r--r--libs/hwui/ProgramCache.h6
-rw-r--r--libs/hwui/Properties.h10
-rw-r--r--libs/hwui/Rect.h47
-rw-r--r--libs/hwui/ResourceCache.h6
-rw-r--r--libs/hwui/SkiaColorFilter.h6
-rw-r--r--libs/hwui/SkiaShader.h6
-rw-r--r--libs/hwui/Snapshot.h26
-rw-r--r--libs/hwui/TextDropShadowCache.h6
-rw-r--r--libs/hwui/Texture.h6
-rw-r--r--libs/hwui/TextureCache.cpp8
-rw-r--r--libs/hwui/TextureCache.h8
-rw-r--r--libs/hwui/Vertex.h6
-rw-r--r--libs/hwui/utils/Compare.h6
-rw-r--r--libs/hwui/utils/GenerationCache.h6
-rw-r--r--libs/hwui/utils/SortedList.h6
-rw-r--r--libs/hwui/utils/SortedListImpl.h6
-rw-r--r--libs/ui/Region.cpp2
43 files changed, 670 insertions, 235 deletions
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 007e7b9dc237..f80fbd8d40d9 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -129,6 +129,7 @@ public class LockPatternView extends View {
private long[] mVibePattern;
private int mAspect;
+ private final Matrix mArrowMatrix = new Matrix();
/**
* Represents a cell in the 3 X 3 matrix of the unlock pattern view.
@@ -923,7 +924,6 @@ public class LockPatternView extends View {
// This assumes that the arrow image is drawn at 12:00 with it's top edge
// coincident with the circle bitmap's top edge.
Bitmap arrow = green ? mBitmapArrowGreenUp : mBitmapArrowRedUp;
- Matrix matrix = new Matrix();
final int cellWidth = mBitmapCircleDefault.getWidth();
final int cellHeight = mBitmapCircleDefault.getHeight();
@@ -933,10 +933,10 @@ public class LockPatternView extends View {
final float angle = (float) Math.toDegrees(theta) + 90.0f;
// compose matrix
- matrix.setTranslate(leftX + offsetX, topY + offsetY); // transform to cell position
- matrix.preRotate(angle, cellWidth / 2.0f, cellHeight / 2.0f); // rotate about cell center
- matrix.preTranslate((cellWidth - arrow.getWidth()) / 2.0f, 0.0f); // translate to 12:00 pos
- canvas.drawBitmap(arrow, matrix, mPaint);
+ mArrowMatrix.setTranslate(leftX + offsetX, topY + offsetY); // transform to cell position
+ mArrowMatrix.preRotate(angle, cellWidth / 2.0f, cellHeight / 2.0f); // rotate about cell center
+ mArrowMatrix.preTranslate((cellWidth - arrow.getWidth()) / 2.0f, 0.0f); // translate to 12:00 pos
+ canvas.drawBitmap(arrow, mArrowMatrix, mPaint);
}
/**
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index d661f7be2d74..29158e512692 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -38,7 +38,7 @@ ifeq ($(USE_OPENGL_RENDERER),true)
LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
- LOCAL_SHARED_LIBRARIES := libcutils libutils libGLESv2 libskia
+ LOCAL_SHARED_LIBRARIES := libcutils libutils libGLESv2 libskia libui
LOCAL_MODULE := libhwui
LOCAL_MODULE_TAGS := optional
LOCAL_PRELINK_MODULE := false
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 0994d82f8661..93c5b346fd41 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -46,18 +46,21 @@ Caches::Caches(): Singleton<Caches>(), blend(false), lastSrcMode(GL_ZERO),
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
mCurrentBuffer = meshBuffer;
+ mRegionMesh = NULL;
}
-/**
- * Binds the VBO used to render simple textured quads.
- */
+Caches::~Caches() {
+ delete[] mRegionMesh;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// VBO
+///////////////////////////////////////////////////////////////////////////////
+
void Caches::bindMeshBuffer() {
bindMeshBuffer(meshBuffer);
}
-/**
- * Binds the specified VBO.
- */
void Caches::bindMeshBuffer(const GLuint buffer) {
if (mCurrentBuffer != buffer) {
glBindBuffer(GL_ARRAY_BUFFER, buffer);
@@ -65,9 +68,6 @@ void Caches::bindMeshBuffer(const GLuint buffer) {
}
}
-/**
- * Unbinds the VBO used to render simple textured quads.
- */
void Caches::unbindMeshBuffer() {
if (mCurrentBuffer) {
glBindBuffer(GL_ARRAY_BUFFER, 0);
@@ -75,5 +75,35 @@ void Caches::unbindMeshBuffer() {
}
}
+TextureVertex* Caches::getRegionMesh() {
+ // Create the mesh, 2 triangles and 4 vertices per rectangle in the region
+ if (!mRegionMesh) {
+ mRegionMesh = new TextureVertex[REGION_MESH_QUAD_COUNT * 4];
+
+ uint16_t* regionIndices = new uint16_t[REGION_MESH_QUAD_COUNT * 6];
+ for (int i = 0; i < REGION_MESH_QUAD_COUNT; i++) {
+ uint16_t quad = i * 4;
+ int index = i * 6;
+ regionIndices[index ] = quad; // top-left
+ regionIndices[index + 1] = quad + 1; // top-right
+ regionIndices[index + 2] = quad + 2; // bottom-left
+ regionIndices[index + 3] = quad + 2; // bottom-left
+ regionIndices[index + 4] = quad + 1; // top-right
+ regionIndices[index + 5] = quad + 3; // bottom-right
+ }
+
+ glGenBuffers(1, &mRegionMeshIndices);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 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);
+ }
+
+ return mRegionMesh;
+}
+
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index ca228674fe2f..c019fd1ee86b 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_CACHES_H
-#define ANDROID_UI_CACHES_H
+#ifndef ANDROID_HWUI_CACHES_H
+#define ANDROID_HWUI_CACHES_H
#ifndef LOG_TAG
#define LOG_TAG "OpenGLRenderer"
@@ -46,6 +46,8 @@ namespace uirenderer {
#define REQUIRED_TEXTURE_UNITS_COUNT 3
+#define REGION_MESH_QUAD_COUNT 512
+
// Generates simple and textured vertices
#define FV(x, y, u, v) { { x, y }, { u, v } }
@@ -77,6 +79,7 @@ struct CacheLogger {
class Caches: public Singleton<Caches> {
Caches();
+ ~Caches();
friend class Singleton<Caches>;
@@ -84,11 +87,33 @@ class Caches: public Singleton<Caches> {
GLuint mCurrentBuffer;
+ // Used to render layers
+ TextureVertex* mRegionMesh;
+ GLuint mRegionMeshIndices;
+
public:
+ /**
+ * Binds the VBO used to render simple textured quads.
+ */
void bindMeshBuffer();
+
+ /**
+ * Binds the specified VBO if needed.
+ */
void bindMeshBuffer(const GLuint buffer);
+
+ /**
+ * Unbinds the VBO used to render simple textured quads.
+ */
void unbindMeshBuffer();
+ /**
+ * Returns the mesh used to draw regions. Calling this method will
+ * bind a VBO of type GL_ELEMENT_ARRAY_BUFFER that contains the
+ * indices for the region mesh.
+ */
+ TextureVertex* getRegionMesh();
+
bool blend;
GLenum lastSrcMode;
GLenum lastDstMode;
@@ -118,7 +143,6 @@ public:
}; // class Caches
}; // namespace uirenderer
-
}; // namespace android
-#endif // ANDROID_UI_CACHES_H
+#endif // ANDROID_HWUI_CACHES_H
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 0dd9c5a3814d..23ccef63c806 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -169,7 +169,8 @@ void DisplayList::replay(OpenGLRenderer& renderer) {
int saveCount = renderer.getSaveCount() - 1;
while (!mReader.eof()) {
- switch (mReader.readInt()) {
+ int op = mReader.readInt();
+ switch (op) {
case AcquireContext: {
renderer.acquireContext();
}
@@ -195,6 +196,11 @@ void DisplayList::replay(OpenGLRenderer& renderer) {
getPaint(), getInt());
}
break;
+ case SaveLayerAlpha: {
+ renderer.saveLayerAlpha(getFloat(), getFloat(), getFloat(), getFloat(),
+ getInt(), getInt());
+ }
+ break;
case Translate: {
renderer.translate(getFloat(), getFloat());
}
@@ -400,6 +406,15 @@ int DisplayListRenderer::saveLayer(float left, float top, float right, float bot
return OpenGLRenderer::save(flags);
}
+int DisplayListRenderer::saveLayerAlpha(float left, float top, float right, float bottom,
+ int alpha, int flags) {
+ addOp(DisplayList::SaveLayerAlpha);
+ addBounds(left, top, right, bottom);
+ addInt(alpha);
+ addInt(flags);
+ return OpenGLRenderer::save(flags);
+}
+
void DisplayListRenderer::translate(float dx, float dy) {
addOp(DisplayList::Translate);
addPoint(dx, dy);
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 6636de62b6f6..fd69fab56d71 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_DISPLAY_LIST_RENDERER_H
-#define ANDROID_UI_DISPLAY_LIST_RENDERER_H
+#ifndef ANDROID_HWUI_DISPLAY_LIST_RENDERER_H
+#define ANDROID_HWUI_DISPLAY_LIST_RENDERER_H
#include <SkChunkAlloc.h>
#include <SkFlattenable.h>
@@ -85,6 +85,7 @@ public:
Restore,
RestoreToCount,
SaveLayer,
+ SaveLayerAlpha,
Translate,
Rotate,
Scale,
@@ -222,6 +223,8 @@ public:
int saveLayer(float left, float top, float right, float bottom,
SkPaint* p, int flags);
+ int saveLayerAlpha(float left, float top, float right, float bottom,
+ int alpha, int flags);
void translate(float dx, float dy);
void rotate(float degrees);
@@ -411,4 +414,4 @@ private:
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_UI_DISPLAY_LIST_RENDERER_H
+#endif // ANDROID_HWUI_DISPLAY_LIST_RENDERER_H
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index d50d36eabaa5..eceb5c1cb0df 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_EXTENSIONS_H
-#define ANDROID_UI_EXTENSIONS_H
+#ifndef ANDROID_HWUI_EXTENSIONS_H
+#define ANDROID_HWUI_EXTENSIONS_H
#include <utils/SortedVector.h>
#include <utils/String8.h>
@@ -93,4 +93,4 @@ private:
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_UI_EXTENSIONS_H
+#endif // ANDROID_HWUI_EXTENSIONS_H
diff --git a/libs/hwui/FboCache.h b/libs/hwui/FboCache.h
index ec4afe9e2c5e..ad6cc3ea96c9 100644
--- a/libs/hwui/FboCache.h
+++ b/libs/hwui/FboCache.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_FBO_CACHE_H
-#define ANDROID_UI_FBO_CACHE_H
+#ifndef ANDROID_HWUI_FBO_CACHE_H
+#define ANDROID_HWUI_FBO_CACHE_H
#include <GLES2/gl2.h>
@@ -76,4 +76,4 @@ private:
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_UI_FBO_CACHE_H
+#endif // ANDROID_HWUI_FBO_CACHE_H
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index e1a236c37868..5224689b3ce7 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -556,6 +556,8 @@ void FontRenderer::issueDrawCommand() {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBufferID);
glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, NULL);
+
+ mDrawn = true;
}
void FontRenderer::appendMeshQuad(float x1, float y1, float z1, float u1, float v1, float x2,
@@ -595,6 +597,13 @@ void FontRenderer::appendMeshQuad(float x1, float y1, float z1, float u1, float
mCurrentQuadIndex++;
+ if (mBounds) {
+ mBounds->left = fmin(mBounds->left, x1);
+ mBounds->top = fmin(mBounds->top, y3);
+ mBounds->right = fmax(mBounds->right, x3);
+ mBounds->bottom = fmax(mBounds->bottom, y1);
+ }
+
if (mCurrentQuadIndex == mMaxNumberOfQuads) {
issueDrawCommand();
mCurrentQuadIndex = 0;
@@ -674,22 +683,27 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const ch
return image;
}
-void FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text,
- uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y) {
+bool FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text,
+ uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, Rect* bounds) {
checkInit();
if (!mCurrentFont) {
LOGE("No font set");
- return;
+ return false;
}
+ mDrawn = false;
+ mBounds = bounds;
mClip = clip;
mCurrentFont->renderUTF(paint, text, startIndex, len, numGlyphs, x, y);
+ mBounds = NULL;
if (mCurrentQuadIndex != 0) {
issueDrawCommand();
mCurrentQuadIndex = 0;
}
+
+ return mDrawn;
}
void FontRenderer::computeGaussianWeights(float* weights, int32_t radius) {
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index f10efad89457..a76cb8633452 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_FONT_RENDERER_H
-#define ANDROID_UI_FONT_RENDERER_H
+#ifndef ANDROID_HWUI_FONT_RENDERER_H
+#define ANDROID_HWUI_FONT_RENDERER_H
#include <utils/String8.h>
#include <utils/String16.h>
@@ -132,8 +132,8 @@ public:
}
void setFont(SkPaint* paint, uint32_t fontId, float fontSize);
- void renderText(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex,
- uint32_t len, int numGlyphs, int x, int y);
+ bool renderText(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex,
+ uint32_t len, int numGlyphs, int x, int y, Rect* bounds);
struct DropShadow {
DropShadow() { };
@@ -257,6 +257,8 @@ protected:
uint32_t mIndexBufferID;
const Rect* mClip;
+ Rect* mBounds;
+ bool mDrawn;
bool mInitialized;
@@ -273,4 +275,4 @@ protected:
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_UI_FONT_RENDERER_H
+#endif // ANDROID_HWUI_FONT_RENDERER_H
diff --git a/libs/hwui/GammaFontRenderer.h b/libs/hwui/GammaFontRenderer.h
index 5fa45cf67e9d..b59ae81817ec 100644
--- a/libs/hwui/GammaFontRenderer.h
+++ b/libs/hwui/GammaFontRenderer.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_GAMMA_FONT_RENDERER_H
-#define ANDROID_UI_GAMMA_FONT_RENDERER_H
+#ifndef ANDROID_HWUI_GAMMA_FONT_RENDERER_H
+#define ANDROID_HWUI_GAMMA_FONT_RENDERER_H
#include <SkPaint.h>
@@ -45,4 +45,4 @@ private:
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_UI_GAMMA_FONT_RENDERER_H
+#endif // ANDROID_HWUI_GAMMA_FONT_RENDERER_H
diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h
index 48877f6d3a7f..c9553f4d6920 100644
--- a/libs/hwui/GradientCache.h
+++ b/libs/hwui/GradientCache.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_GRADIENT_CACHE_H
-#define ANDROID_UI_GRADIENT_CACHE_H
+#ifndef ANDROID_HWUI_GRADIENT_CACHE_H
+#define ANDROID_HWUI_GRADIENT_CACHE_H
#include <SkShader.h>
@@ -93,4 +93,4 @@ private:
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_UI_GRADIENT_CACHE_H
+#endif // ANDROID_HWUI_GRADIENT_CACHE_H
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 2afe2faad39a..a780183a1c33 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -14,13 +14,15 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_LAYER_H
-#define ANDROID_UI_LAYER_H
+#ifndef ANDROID_HWUI_LAYER_H
+#define ANDROID_HWUI_LAYER_H
#include <sys/types.h>
#include <GLES2/gl2.h>
+#include <ui/Region.h>
+
#include <SkXfermode.h>
#include "Rect.h"
@@ -85,9 +87,15 @@ struct Layer {
* Height of the layer texture.
*/
uint32_t height;
+
+ /**
+ * Dirty region indicating what parts of the layer
+ * have been drawn.
+ */
+ Region region;
}; // struct Layer
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_UI_LAYER_H
+#endif // ANDROID_HWUI_LAYER_H
diff --git a/libs/hwui/LayerCache.h b/libs/hwui/LayerCache.h
index ae792ab518ce..4df8ab3b4b38 100644
--- a/libs/hwui/LayerCache.h
+++ b/libs/hwui/LayerCache.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_LAYER_CACHE_H
-#define ANDROID_UI_LAYER_CACHE_H
+#ifndef ANDROID_HWUI_LAYER_CACHE_H
+#define ANDROID_HWUI_LAYER_CACHE_H
#include "Layer.h"
#include "utils/SortedList.h"
@@ -138,4 +138,4 @@ private:
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_UI_LAYER_CACHE_H
+#endif // ANDROID_HWUI_LAYER_CACHE_H
diff --git a/libs/hwui/Line.h b/libs/hwui/Line.h
index c52935409c40..5c6f3d879dca 100644
--- a/libs/hwui/Line.h
+++ b/libs/hwui/Line.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_LINE_H
-#define ANDROID_UI_LINE_H
+#ifndef ANDROID_HWUI_LINE_H
+#define ANDROID_HWUI_LINE_H
#include <GLES2/gl2.h>
@@ -123,4 +123,4 @@ private:
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_UI_LINE_H
+#endif // ANDROID_HWUI_LINE_H
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index 83ea615d2263..7462d5bae208 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -271,6 +271,19 @@ void Matrix4::mapRect(Rect& r) const {
MUL_ADD_STORE(r.right, data[kScaleX], data[kTranslateX]);
MUL_ADD_STORE(r.top, data[kScaleY], data[kTranslateY]);
MUL_ADD_STORE(r.bottom, data[kScaleY], data[kTranslateY]);
+
+ if (r.left > r.right) {
+ float x = r.left;
+ r.left = r.right;
+ r.right = x;
+ }
+
+ if (r.top > r.bottom) {
+ float y = r.top;
+ r.top = r.bottom;
+ r.bottom = y;
+ }
+
return;
}
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index fe8115966909..d678bd0e899e 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_MATRIX_H
-#define ANDROID_UI_MATRIX_H
+#ifndef ANDROID_HWUI_MATRIX_H
+#define ANDROID_HWUI_MATRIX_H
#include <SkMatrix.h>
@@ -137,4 +137,4 @@ typedef Matrix4 mat4;
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_UI_MATRIX_H
+#endif // ANDROID_HWUI_MATRIX_H
diff --git a/libs/hwui/OpenGLDebugRenderer.h b/libs/hwui/OpenGLDebugRenderer.h
index ce6a4aaa1d42..7787ff1c4280 100644
--- a/libs/hwui/OpenGLDebugRenderer.h
+++ b/libs/hwui/OpenGLDebugRenderer.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_OPENGL_DEBUG_RENDERER_H
-#define ANDROID_UI_OPENGL_DEBUG_RENDERER_H
+#ifndef ANDROID_HWUI_OPENGL_DEBUG_RENDERER_H
+#define ANDROID_HWUI_OPENGL_DEBUG_RENDERER_H
#include "OpenGLRenderer.h"
@@ -66,4 +66,4 @@ private:
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_UI_OPENGL_DEBUG_RENDERER_H
+#endif // ANDROID_HWUI_OPENGL_DEBUG_RENDERER_H
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index b16713109f12..0f0316f45ca4 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -26,6 +26,8 @@
#include <utils/Log.h>
#include <utils/StopWatch.h>
+#include <ui/Rect.h>
+
#include "OpenGLRenderer.h"
namespace android {
@@ -285,7 +287,7 @@ int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bottom,
int alpha, int flags) {
- if (alpha == 0xff) {
+ if (alpha >= 255 - ALPHA_THRESHOLD) {
return saveLayer(left, top, right, bottom, NULL, flags);
} else {
SkPaint paint;
@@ -377,7 +379,6 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
bounds.getHeight() > mCaches.maxTextureSize) {
snapshot->invisible = true;
} else {
- // TODO: Should take the mode into account
snapshot->invisible = snapshot->previous->invisible ||
(alpha <= ALPHA_THRESHOLD && fboLayer);
}
@@ -387,8 +388,7 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
return false;
}
- glActiveTexture(GL_TEXTURE0);
-
+ glActiveTexture(gTextureUnits[0]);
Layer* layer = mCaches.layerCache.get(bounds.getWidth(), bounds.getHeight());
if (!layer) {
return false;
@@ -405,56 +405,7 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
snapshot->layer = layer;
if (fboLayer) {
- layer->fbo = mCaches.fboCache.get();
-
- snapshot->flags |= Snapshot::kFlagIsFboLayer;
- snapshot->fbo = layer->fbo;
- snapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
- snapshot->resetClip(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
- snapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
- snapshot->height = bounds.getHeight();
- snapshot->flags |= Snapshot::kFlagDirtyOrtho;
- snapshot->orthoMatrix.load(mOrthoMatrix);
-
- // Bind texture to FBO
- glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo);
- glBindTexture(GL_TEXTURE_2D, layer->texture);
-
- // Initialize the texture if needed
- if (layer->empty) {
- layer->empty = false;
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->width, layer->height, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, NULL);
- }
-
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
- layer->texture, 0);
-
-#if DEBUG_LAYERS
- GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
- if (status != GL_FRAMEBUFFER_COMPLETE) {
- LOGE("Framebuffer incomplete (GL error code 0x%x)", status);
-
- glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
- glDeleteTextures(1, &layer->texture);
- mCaches.fboCache.put(layer->fbo);
-
- delete layer;
-
- return false;
- }
-#endif
-
- // Clear the FBO
- glScissor(0.0f, 0.0f, bounds.getWidth() + 1.0f, bounds.getHeight() + 1.0f);
- glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
- glClear(GL_COLOR_BUFFER_BIT);
-
- dirtyClip();
-
- // Change the ortho projection
- glViewport(0, 0, bounds.getWidth(), bounds.getHeight());
- mOrthoMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f);
+ return createFboLayer(layer, bounds, snapshot, previousFbo);
} else {
// Copy the framebuffer into the layer
glBindTexture(GL_TEXTURE_2D, layer->texture);
@@ -475,6 +426,82 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
return true;
}
+bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, sp<Snapshot> snapshot,
+ GLuint previousFbo) {
+ layer->fbo = 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);
+ clip.intersect(*snapshot->clipRect);
+ clip.snapToPixelBoundaries();
+ clip.intersect(snapshot->previous->viewport);
+
+ mat4 inverse;
+ inverse.loadInverse(*mSnapshot->transform);
+
+ inverse.mapRect(clip);
+ clip.snapToPixelBoundaries();
+ clip.intersect(bounds);
+
+ snapshot->flags |= Snapshot::kFlagIsFboLayer;
+ snapshot->fbo = layer->fbo;
+ snapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
+ //snapshot->resetClip(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
+ snapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
+ snapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
+ snapshot->height = bounds.getHeight();
+ snapshot->flags |= Snapshot::kFlagDirtyOrtho;
+ snapshot->orthoMatrix.load(mOrthoMatrix);
+
+ // Bind texture to FBO
+ glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo);
+ glBindTexture(GL_TEXTURE_2D, layer->texture);
+
+ // Initialize the texture if needed
+ if (layer->empty) {
+ layer->empty = false;
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->width, layer->height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ }
+
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ layer->texture, 0);
+
+#if DEBUG_LAYERS_AS_REGIONS
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ LOGE("Framebuffer incomplete (GL error code 0x%x)", status);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
+ glDeleteTextures(1, &layer->texture);
+ mCaches.fboCache.put(layer->fbo);
+
+ delete layer;
+
+ return false;
+ }
+#endif
+
+ // Clear the FBO, expand the clear region by 1 to get nice bilinear filtering
+ glScissor(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f,
+ clip.getWidth() + 2.0f, clip.getHeight() + 2.0f);
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ dirtyClip();
+
+ // Change the ortho projection
+ glViewport(0, 0, bounds.getWidth(), bounds.getHeight());
+ mOrthoMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f);
+
+ return true;
+}
+
/**
* Read the documentation of createLayer() before doing anything in this method.
*/
@@ -484,43 +511,37 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
return;
}
- const bool fboLayer = current->flags & SkCanvas::kClipToLayer_SaveFlag;
+ const bool fboLayer = current->flags & Snapshot::kFlagIsFboLayer;
if (fboLayer) {
// Unbind current FBO and restore previous one
glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo);
}
- // Restore the clip from the previous snapshot
- Rect& clip(*previous->clipRect);
- clip.snapToPixelBoundaries();
- glScissor(clip.left, previous->height - clip.bottom, clip.getWidth(), clip.getHeight());
-
Layer* layer = current->layer;
const Rect& rect = layer->layer;
if (!fboLayer && layer->alpha < 255) {
drawColorRect(rect.left, rect.top, rect.right, rect.bottom,
layer->alpha << 24, SkXfermode::kDstIn_Mode, true);
+ // Required below, composeLayerRect() will divide by 255
+ layer->alpha = 255;
}
- const Rect& texCoords = layer->texCoords;
mCaches.unbindMeshBuffer();
- resetDrawTextureTexCoords(texCoords.left, texCoords.top, texCoords.right, texCoords.bottom);
glActiveTexture(gTextureUnits[0]);
+
+ // When the layer is stored in an FBO, we can save a bit of fillrate by
+ // drawing only the dirty region
if (fboLayer) {
- drawTextureMesh(rect.left, rect.top, rect.right, rect.bottom, layer->texture,
- layer->alpha / 255.0f, layer->mode, layer->blend, &mMeshVertices[0].position[0],
- &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount);
+ dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *previous->transform);
+ composeLayerRegion(layer, rect);
} else {
- drawTextureMesh(rect.left, rect.top, rect.right, rect.bottom, layer->texture,
- 1.0f, layer->mode, layer->blend, &mMeshVertices[0].position[0],
- &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount, true, true);
+ dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
+ composeLayerRect(layer, rect, true);
}
- resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
-
if (fboLayer) {
// Detach the texture from the FBO
glBindFramebuffer(GL_FRAMEBUFFER, current->fbo);
@@ -541,6 +562,159 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
}
}
+void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
+ const Rect& texCoords = layer->texCoords;
+ resetDrawTextureTexCoords(texCoords.left, texCoords.top, texCoords.right, texCoords.bottom);
+
+ drawTextureMesh(rect.left, rect.top, rect.right, rect.bottom, layer->texture,
+ layer->alpha / 255.0f, layer->mode, layer->blend, &mMeshVertices[0].position[0],
+ &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount, swap, swap);
+
+ resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
+}
+
+void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
+#if RENDER_LAYERS_AS_REGIONS
+ if (layer->region.isRect()) {
+ composeLayerRect(layer, rect);
+ layer->region.clear();
+ return;
+ }
+
+ if (!layer->region.isEmpty()) {
+ size_t count;
+ const android::Rect* rects = layer->region.getArray(&count);
+
+ setupDraw();
+
+ ProgramDescription description;
+ description.hasTexture = true;
+
+ const float alpha = layer->alpha / 255.0f;
+ const bool setColor = description.setColor(alpha, alpha, alpha, alpha);
+ chooseBlending(layer->blend || layer->alpha < 255, layer->mode, description, false);
+
+ useProgram(mCaches.programCache.get(description));
+
+ // Texture
+ bindTexture(layer->texture);
+ glUniform1i(mCaches.currentProgram->getUniform("sampler"), 0);
+
+ // Always premultiplied
+ if (setColor) {
+ mCaches.currentProgram->setColor(alpha, alpha, alpha, alpha);
+ }
+
+ // Mesh
+ int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords");
+ glEnableVertexAttribArray(texCoordsSlot);
+
+ mModelView.loadIdentity();
+ mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
+
+ const float texX = 1.0f / float(layer->width);
+ const float texY = 1.0f / float(layer->height);
+
+ TextureVertex* mesh = mCaches.getRegionMesh();
+ GLsizei numQuads = 0;
+
+ glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
+ gMeshStride, &mesh[0].position[0]);
+ glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE,
+ gMeshStride, &mesh[0].texture[0]);
+
+ for (size_t i = 0; i < count; i++) {
+ const android::Rect* r = &rects[i];
+
+ const float u1 = r->left * texX;
+ const float v1 = (rect.getHeight() - r->top) * texY;
+ const float u2 = r->right * texX;
+ const float v2 = (rect.getHeight() - r->bottom) * texY;
+
+ // TODO: Reject quads outside of the clip
+ TextureVertex::set(mesh++, r->left, r->top, u1, v1);
+ TextureVertex::set(mesh++, r->right, r->top, u2, v1);
+ TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
+ TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
+
+ numQuads++;
+
+ if (numQuads >= REGION_MESH_QUAD_COUNT) {
+ glDrawElements(GL_TRIANGLES, numQuads * 6, GL_UNSIGNED_SHORT, NULL);
+ numQuads = 0;
+ mesh = mCaches.getRegionMesh();
+ }
+ }
+
+ if (numQuads > 0) {
+ glDrawElements(GL_TRIANGLES, numQuads * 6, GL_UNSIGNED_SHORT, NULL);
+ }
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glDisableVertexAttribArray(texCoordsSlot);
+
+#if DEBUG_LAYERS_AS_REGIONS
+ uint32_t colors[] = {
+ 0x7fff0000, 0x7f00ff00,
+ 0x7f0000ff, 0x7fff00ff,
+ };
+
+ int offset = 0;
+ int32_t top = rects[0].top;
+ int i = 0;
+
+ for (size_t i = 0; i < count; i++) {
+ if (top != rects[i].top) {
+ offset ^= 0x2;
+ top = rects[i].top;
+ }
+
+ Rect r(rects[i].left, rects[i].top, rects[i].right, rects[i].bottom);
+ drawColorRect(r.left, r.top, r.right, r.bottom, colors[offset + (i & 0x1)],
+ SkXfermode::kSrcOver_Mode);
+ }
+#endif
+
+ layer->region.clear();
+ }
+#else
+ composeLayerRect(layer, rect);
+#endif
+}
+
+void OpenGLRenderer::dirtyLayer(const float left, const float top,
+ const float right, const float bottom, const mat4 transform) {
+#if RENDER_LAYERS_AS_REGIONS
+ if ((mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region) {
+ Rect bounds(left, top, right, bottom);
+ transform.mapRect(bounds);
+ bounds.intersect(*mSnapshot->clipRect);
+ bounds.snapToPixelBoundaries();
+
+ android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
+ if (!dirty.isEmpty()) {
+ mSnapshot->region->orSelf(dirty);
+ }
+ }
+#endif
+}
+
+void OpenGLRenderer::dirtyLayer(const float left, const float top,
+ const float right, const float bottom) {
+#if RENDER_LAYERS_AS_REGIONS
+ if ((mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region) {
+ Rect bounds(left, top, right, bottom);
+ bounds.intersect(*mSnapshot->clipRect);
+ bounds.snapToPixelBoundaries();
+
+ android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
+ if (!dirty.isEmpty()) {
+ mSnapshot->region->orSelf(dirty);
+ }
+ }
+#endif
+}
+
void OpenGLRenderer::setupDraw() {
clearLayerRegions();
if (mDirtyClip) {
@@ -551,21 +725,26 @@ void OpenGLRenderer::setupDraw() {
void OpenGLRenderer::clearLayerRegions() {
if (mLayers.size() == 0 || mSnapshot->invisible) return;
+ Rect clipRect(*mSnapshot->clipRect);
+ clipRect.snapToPixelBoundaries();
+
for (uint32_t i = 0; i < mLayers.size(); i++) {
Rect* bounds = mLayers.itemAt(i);
-
- // Clear the framebuffer where the layer will draw
- glScissor(bounds->left, mSnapshot->height - bounds->bottom,
- bounds->getWidth(), bounds->getHeight());
- glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
- glClear(GL_COLOR_BUFFER_BIT);
+ if (clipRect.intersects(*bounds)) {
+ // Clear the framebuffer where the layer will draw
+ glScissor(bounds->left, mSnapshot->height - bounds->bottom,
+ bounds->getWidth(), bounds->getHeight());
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // Restore the clip
+ dirtyClip();
+ }
delete bounds;
}
- mLayers.clear();
- // Restore the clip
- dirtyClip();
+ mLayers.clear();
}
///////////////////////////////////////////////////////////////////////////////
@@ -678,7 +857,12 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* pai
if (!texture) return;
const AutoTexture autoCleanup(texture);
- drawTextureRect(r.left, r.top, r.right, r.bottom, texture, paint);
+ // This could be done in a cheaper way, all we need is pass the matrix
+ // to the vertex shader. The save/restore is a bit overkill.
+ save(SkCanvas::kMatrix_SaveFlag);
+ concatMatrix(matrix);
+ drawTextureRect(0.0f, 0.0f, bitmap->width(), bitmap->height(), texture, paint);
+ restore();
}
void OpenGLRenderer::drawBitmap(SkBitmap* bitmap,
@@ -738,11 +922,21 @@ void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int
right - left, bottom - top, xDivs, yDivs, colors, width, height, numColors);
if (mesh) {
- // Specify right and bottom as +1.0f from left/top to prevent scaling since the
- // patch mesh already defines the final size
- drawTextureMesh(left, top, left + 1.0f, top + 1.0f, texture->id, alpha / 255.0f,
+ // Mark the current layer dirty where we are going to draw the patch
+ if ((mSnapshot->flags & Snapshot::kFlagFboTarget) &&
+ mSnapshot->region && mesh->hasEmptyQuads) {
+ const size_t count = mesh->quads.size();
+ for (size_t i = 0; i < count; i++) {
+ Rect bounds = mesh->quads.itemAt(i);
+ dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom,
+ *mSnapshot->transform);
+ }
+ }
+
+ drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f,
mode, texture->blend, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset,
- GL_TRIANGLES, mesh->verticesCount, false, false, mesh->meshBuffer);
+ GL_TRIANGLES, mesh->verticesCount, false, false, mesh->meshBuffer,
+ true, !mesh->hasEmptyQuads);
}
}
@@ -801,6 +995,7 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
mModelView.scale(length, strokeWidth, 1.0f);
}
mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
+ // TODO: Add bounds to the layer's region
if (mShader) {
mShader->updateTransforms(mCaches.currentProgram, mModelView, *mSnapshot);
@@ -904,13 +1099,34 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
// Assume that the modelView matrix does not force scales, rotates, etc.
const bool linearFilter = mSnapshot->transform->changesBounds();
+
+ // Dimensions are set to (0,0), the layer (if any) won't be dirtied
setupTextureAlpha8(fontRenderer.getTexture(linearFilter), 0, 0, textureUnit,
x, y, r, g, b, a, mode, false, true, NULL, NULL);
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
+ bool hasLayer = (mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region;
+#else
+ bool hasLayer = false;
+#endif
mCaches.unbindMeshBuffer();
- fontRenderer.renderText(paint, &clip, text, 0, bytesCount, count, x, y);
+ if (fontRenderer.renderText(paint, &clip, text, 0, bytesCount, count, x, y,
+ hasLayer ? &bounds : NULL)) {
+#if RENDER_LAYERS_AS_REGIONS
+ if (hasLayer) {
+ mSnapshot->transform->mapRect(bounds);
+ bounds.intersect(*mSnapshot->clipRect);
+ bounds.snapToPixelBoundaries();
+
+ android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
+ mSnapshot->region->orSelf(dirty);
+ }
+#endif
+ }
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords"));
@@ -1081,7 +1297,12 @@ void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t
} else {
mModelView.loadIdentity();
}
+
mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
+ if (width > 0 && height > 0) {
+ dirtyLayer(x, y, x + width, y + height, *mSnapshot->transform);
+ }
+
if (setColor) {
mCaches.currentProgram->setColor(r, g, b, a);
}
@@ -1214,9 +1435,11 @@ void OpenGLRenderer::setupColorRect(float left, float top, float right, float bo
mModelView.scale(right - left, bottom - top, 1.0f);
if (!ignoreTransform) {
mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
+ dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
} else {
mat4 identity;
mCaches.currentProgram->set(mOrthoMatrix, mModelView, identity);
+ dirtyLayer(left, top, right, bottom);
}
mCaches.currentProgram->setColor(r, g, b, a);
@@ -1251,7 +1474,7 @@ void OpenGLRenderer::drawTextureRect(float left, float top, float right, float b
void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom,
GLuint texture, float alpha, SkXfermode::Mode mode, bool blend,
GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
- bool swapSrcDst, bool ignoreTransform, GLuint vbo) {
+ bool swapSrcDst, bool ignoreTransform, GLuint vbo, bool ignoreScale, bool dirty) {
setupDraw();
ProgramDescription description;
@@ -1262,16 +1485,20 @@ void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float b
}
mModelView.loadTranslate(left, top, 0.0f);
- mModelView.scale(right - left, bottom - top, 1.0f);
+ if (!ignoreScale) {
+ mModelView.scale(right - left, bottom - top, 1.0f);
+ }
chooseBlending(blend || alpha < 1.0f, mode, description, swapSrcDst);
useProgram(mCaches.programCache.get(description));
if (!ignoreTransform) {
mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
+ if (dirty) dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
} else {
- mat4 m;
- mCaches.currentProgram->set(mOrthoMatrix, mModelView, m);
+ mat4 identity;
+ mCaches.currentProgram->set(mOrthoMatrix, mModelView, identity);
+ if (dirty) dirtyLayer(left, top, right, bottom);
}
// Texture
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 3492d2c132b9..2d612d43ae08 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_OPENGL_RENDERER_H
-#define ANDROID_UI_OPENGL_RENDERER_H
+#ifndef ANDROID_HWUI_OPENGL_RENDERER_H
+#define ANDROID_HWUI_OPENGL_RENDERER_H
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
@@ -50,6 +50,10 @@ namespace uirenderer {
// Debug
#define DEBUG_OPENGL 1
+// If turned on, layers drawn inside FBOs are optimized with regions
+#define RENDER_LAYERS_AS_REGIONS 0
+#define DEBUG_LAYERS_AS_REGIONS 0
+
///////////////////////////////////////////////////////////////////////////////
// Renderer
///////////////////////////////////////////////////////////////////////////////
@@ -176,6 +180,34 @@ private:
int alpha, SkXfermode::Mode mode, int flags, GLuint previousFbo);
/**
+ * Creates a new layer stored in the specified snapshot as an FBO.
+ *
+ * @param layer The layer to store as an FBO
+ * @param snapshot The snapshot associated with the new layer
+ * @param bounds The bounds of the layer
+ * @param previousFbo The name of the current framebuffer
+ */
+ bool createFboLayer(Layer* layer, Rect& bounds, sp<Snapshot> snapshot,
+ GLuint previousFbo);
+
+ /**
+ * Compose the specified layer as a region.
+ *
+ * @param layer The layer to compose
+ * @param rect The layer's bounds
+ */
+ void composeLayerRegion(Layer* layer, const Rect& rect);
+
+ /**
+ * Compose the specified layer as a simple rectangle.
+ *
+ * @param layer The layer to compose
+ * @param rect The layer's bounds
+ * @param swap If true, the source and destination are swapped
+ */
+ void composeLayerRect(Layer* layer, const Rect& rect, bool swap = false);
+
+ /**
* Clears all the regions corresponding to the current list of layers.
* This method MUST be invoked before any drawing operation.
*/
@@ -192,7 +224,7 @@ private:
* @param color The rectangle's ARGB color, defined as a packed 32 bits word
* @param mode The Skia xfermode to use
* @param ignoreTransform True if the current transform should be ignored
- * @paran ignoreBlending True if the blending is set by the caller
+ * @param ignoreBlending True if the blending is set by the caller
*/
void drawColorRect(float left, float top, float right, float bottom,
int color, SkXfermode::Mode mode, bool ignoreTransform = false);
@@ -252,11 +284,14 @@ private:
* @param swapSrcDst Whether or not the src and dst blending operations should be swapped
* @param ignoreTransform True if the current transform should be ignored
* @param vbo The VBO used to draw the mesh
+ * @param ignoreScale True if the model view matrix should not be scaled
+ * @param dirty True if calling this method should dirty the current layer
*/
void drawTextureMesh(float left, float top, float right, float bottom, GLuint texture,
float alpha, SkXfermode::Mode mode, bool blend,
GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
- bool swapSrcDst = false, bool ignoreTransform = false, GLuint vbo = 0);
+ bool swapSrcDst = false, bool ignoreTransform = false, GLuint vbo = 0,
+ bool ignoreScale = false, bool dirty = true);
/**
* Prepares the renderer to draw the specified shadow. The active texture
@@ -411,6 +446,18 @@ private:
mDirtyClip = true;
}
+ /**
+ * Mark the layer as dirty at the specified coordinates. The coordinates
+ * are transformed with the supplied matrix.
+ */
+ void dirtyLayer(const float left, const float top, const float right, const float bottom,
+ const mat4 transform);
+
+ /**
+ * Mark the layer as dirty at the specified coordinates.
+ */
+ void dirtyLayer(const float left, const float top, const float right, const float bottom);
+
// Dimensions of the drawing surface
int mWidth, mHeight;
@@ -462,4 +509,4 @@ private:
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_UI_OPENGL_RENDERER_H
+#endif // ANDROID_HWUI_OPENGL_RENDERER_H
diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp
index 3d21431bfd8d..9b2d47656ca9 100644
--- a/libs/hwui/Patch.cpp
+++ b/libs/hwui/Patch.cpp
@@ -34,6 +34,7 @@ Patch::Patch(const uint32_t xCount, const uint32_t yCount, const int8_t emptyQua
// 2 triangles per patch, 3 vertices per triangle
verticesCount = ((xCount + 1) * (yCount + 1) - emptyQuads) * 2 * 3;
mVertices = new TextureVertex[verticesCount];
+ hasEmptyQuads = emptyQuads > 0;
glGenBuffers(1, &meshBuffer);
}
@@ -51,6 +52,8 @@ 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) {
+ if (hasEmptyQuads) quads.clear();
+
const uint32_t xStretchCount = (width + 1) >> 1;
const uint32_t yStretchCount = (height + 1) >> 1;
@@ -118,7 +121,7 @@ void Patch::updateVertices(const float bitmapWidth, const float bitmapHeight,
mVertices, GL_STATIC_DRAW);
}
-inline void Patch::generateRow(TextureVertex*& vertex, float y1, float y2, float v1, float v2,
+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 previousStepX = 0.0f;
@@ -150,12 +153,17 @@ inline void Patch::generateRow(TextureVertex*& vertex, float y1, float y2, float
generateQuad(vertex, x1, y1, width, y2, u1, v1, 1.0f, v2, quadCount, colorKey);
}
-inline void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
+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) {
return;
}
+ if (hasEmptyQuads) {
+ Rect bounds(x1, y1, x2, y2);
+ quads.add(bounds);
+ }
+
// Left triangle
TextureVertex::set(vertex++, x1, y1, u1, v1);
TextureVertex::set(vertex++, x2, y1, u2, v1);
diff --git a/libs/hwui/Patch.h b/libs/hwui/Patch.h
index ce8989379742..1e78b2fcd4ea 100644
--- a/libs/hwui/Patch.h
+++ b/libs/hwui/Patch.h
@@ -14,13 +14,16 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_PATCH_H
-#define ANDROID_UI_PATCH_H
+#ifndef ANDROID_HWUI_PATCH_H
+#define ANDROID_HWUI_PATCH_H
#include <sys/types.h>
#include <GLES2/gl2.h>
+#include <utils/Vector.h>
+
+#include "Rect.h"
#include "Vertex.h"
#include "utils/Compare.h"
@@ -96,15 +99,17 @@ struct Patch {
GLuint meshBuffer;
uint32_t verticesCount;
+ Vector<Rect> quads;
+ bool hasEmptyQuads;
private:
TextureVertex* mVertices;
- static inline void generateRow(TextureVertex*& vertex, float y1, float y2,
+ 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);
- static inline void generateQuad(TextureVertex*& vertex,
+ 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);
@@ -113,4 +118,4 @@ private:
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_UI_PATCH_H
+#endif // ANDROID_HWUI_PATCH_H
diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h
index f4eeb09d746a..deba40d88c58 100644
--- a/libs/hwui/PatchCache.h
+++ b/libs/hwui/PatchCache.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_PATCH_CACHE_H
-#define ANDROID_UI_PATCH_CACHE_H
+#ifndef ANDROID_HWUI_PATCH_CACHE_H
+#define ANDROID_HWUI_PATCH_CACHE_H
#include <utils/KeyedVector.h>
@@ -62,4 +62,4 @@ private:
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_UI_PATCH_CACHE_H
+#endif // ANDROID_HWUI_PATCH_CACHE_H
diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h
index 9a5fc45fb6bd..db5ce0833635 100644
--- a/libs/hwui/PathCache.h
+++ b/libs/hwui/PathCache.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_PATH_CACHE_H
-#define ANDROID_UI_PATH_CACHE_H
+#ifndef ANDROID_HWUI_PATH_CACHE_H
+#define ANDROID_HWUI_PATH_CACHE_H
#include <SkBitmap.h>
#include <SkPaint.h>
@@ -170,4 +170,4 @@ private:
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_UI_PATH_CACHE_H
+#endif // ANDROID_HWUI_PATH_CACHE_H
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index 25674c65f926..baed5fd7ea8e 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -22,12 +22,6 @@ namespace android {
namespace uirenderer {
///////////////////////////////////////////////////////////////////////////////
-// Shaders
-///////////////////////////////////////////////////////////////////////////////
-
-#define SHADER_SOURCE(name, source) const char* name = #source
-
-///////////////////////////////////////////////////////////////////////////////
// Base program
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index 026097c7cbe2..5981662ad8fa 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_PROGRAM_H
-#define ANDROID_UI_PROGRAM_H
+#ifndef ANDROID_HWUI_PROGRAM_H
+#define ANDROID_HWUI_PROGRAM_H
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
@@ -131,4 +131,4 @@ private:
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_UI_PROGRAM_H
+#endif // ANDROID_HWUI_PROGRAM_H
diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h
index 9cb13b391f63..186e8696d555 100644
--- a/libs/hwui/ProgramCache.h
+++ b/libs/hwui/ProgramCache.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_PROGRAM_CACHE_H
-#define ANDROID_UI_PROGRAM_CACHE_H
+#ifndef ANDROID_HWUI_PROGRAM_CACHE_H
+#define ANDROID_HWUI_PROGRAM_CACHE_H
#include <utils/KeyedVector.h>
#include <utils/Log.h>
@@ -258,4 +258,4 @@ private:
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_UI_PROGRAM_CACHE_H
+#endif // ANDROID_HWUI_PROGRAM_CACHE_H
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index db3cb4d1e460..813392bd9a83 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_PROPERTIES_H
-#define ANDROID_UI_PROPERTIES_H
+#ifndef ANDROID_HWUI_PROPERTIES_H
+#define ANDROID_HWUI_PROPERTIES_H
#include <cutils/properties.h>
@@ -45,15 +45,15 @@
#define MB(s) s * 1024 * 1024
#define DEFAULT_TEXTURE_CACHE_SIZE 20.0f
-#define DEFAULT_LAYER_CACHE_SIZE 6.0f
+#define DEFAULT_LAYER_CACHE_SIZE 8.0f
#define DEFAULT_PATH_CACHE_SIZE 4.0f
#define DEFAULT_PATCH_CACHE_SIZE 512
#define DEFAULT_GRADIENT_CACHE_SIZE 0.5f
#define DEFAULT_DROP_SHADOW_CACHE_SIZE 2.0f
-#define DEFAULT_FBO_CACHE_SIZE 25
+#define DEFAULT_FBO_CACHE_SIZE 12
#define DEFAULT_TEXT_GAMMA 1.4f
#define DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD 64
#define DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD 192
-#endif // ANDROID_UI_PROPERTIES_H
+#endif // ANDROID_HWUI_PROPERTIES_H
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index 8f3655cbe067..71951b7a3cc8 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -14,8 +14,10 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_RECT_H
-#define ANDROID_UI_RECT_H
+#ifndef ANDROID_HWUI_RECT_H
+#define ANDROID_HWUI_RECT_H
+
+#include <cmath>
#include <utils/Log.h>
@@ -32,25 +34,35 @@ struct Rect {
float right;
float bottom;
- Rect():
+ // Used by Region
+ typedef float value_type;
+
+ inline Rect():
left(0),
top(0),
right(0),
bottom(0) {
}
- Rect(float left, float top, float right, float bottom):
+ inline Rect(float left, float top, float right, float bottom):
left(left),
top(top),
right(right),
bottom(bottom) {
}
- Rect(const Rect& r) {
+ inline Rect(float width, float height):
+ left(0.0f),
+ top(0.0f),
+ right(width),
+ bottom(height) {
+ }
+
+ inline Rect(const Rect& r) {
set(r);
}
- Rect(Rect& r) {
+ inline Rect(Rect& r) {
set(r);
}
@@ -72,22 +84,26 @@ struct Rect {
return memcmp(&a, &b, sizeof(a));
}
- bool isEmpty() const {
+ inline void clear() {
+ left = top = right = bottom = 0.0f;
+ }
+
+ inline bool isEmpty() const {
return left >= right || top >= bottom;
}
- void setEmpty() {
- memset(this, 0, sizeof(*this));
+ inline void setEmpty() {
+ left = top = right = bottom = 0.0f;
}
- void set(float left, float top, float right, float bottom) {
+ inline void set(float left, float top, float right, float bottom) {
this->left = left;
this->right = right;
this->top = top;
this->bottom = bottom;
}
- void set(const Rect& r) {
+ inline void set(const Rect& r) {
set(r.left, r.top, r.right, r.bottom);
}
@@ -148,6 +164,13 @@ struct Rect {
return false;
}
+ void translate(float dx, float dy) {
+ left += dx;
+ right += dx;
+ top += dy;
+ bottom += dy;
+ }
+
void snapToPixelBoundaries() {
left = floorf(left + 0.5f);
top = floorf(top + 0.5f);
@@ -164,4 +187,4 @@ struct Rect {
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_UI_RECT_H
+#endif // ANDROID_HWUI_RECT_H
diff --git a/libs/hwui/ResourceCache.h b/libs/hwui/ResourceCache.h
index d9b3718133fe..2256fd168819 100644
--- a/libs/hwui/ResourceCache.h
+++ b/libs/hwui/ResourceCache.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_RESOURCE_CACHE_H
-#define ANDROID_UI_RESOURCE_CACHE_H
+#ifndef ANDROID_HWUI_RESOURCE_CACHE_H
+#define ANDROID_HWUI_RESOURCE_CACHE_H
#include <SkBitmap.h>
#include <SkiaColorFilter.h>
@@ -75,4 +75,4 @@ private:
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_UI_RESOURCE_CACHE_H
+#endif // ANDROID_HWUI_RESOURCE_CACHE_H
diff --git a/libs/hwui/SkiaColorFilter.h b/libs/hwui/SkiaColorFilter.h
index 17f49f94ab4e..bf45e13bc0f2 100644
--- a/libs/hwui/SkiaColorFilter.h
+++ b/libs/hwui/SkiaColorFilter.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_SKIA_COLOR_FILTER_H
-#define ANDROID_UI_SKIA_COLOR_FILTER_H
+#ifndef ANDROID_HWUI_SKIA_COLOR_FILTER_H
+#define ANDROID_HWUI_SKIA_COLOR_FILTER_H
#include <GLES2/gl2.h>
#include <SkColorFilter.h>
@@ -123,4 +123,4 @@ private:
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_UI_SKIA_COLOR_FILTER_H
+#endif // ANDROID_HWUI_SKIA_COLOR_FILTER_H
diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h
index 4cd1b8b27f85..1d884ab10b3d 100644
--- a/libs/hwui/SkiaShader.h
+++ b/libs/hwui/SkiaShader.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_SKIA_SHADER_H
-#define ANDROID_UI_SKIA_SHADER_H
+#ifndef ANDROID_HWUI_SKIA_SHADER_H
+#define ANDROID_HWUI_SKIA_SHADER_H
#include <SkShader.h>
#include <SkXfermode.h>
@@ -216,4 +216,4 @@ private:
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_UI_SKIA_SHADER_H
+#endif // ANDROID_HWUI_SKIA_SHADER_H
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 2da195016c3a..9f78063cc8da 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -14,16 +14,16 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_SNAPSHOT_H
-#define ANDROID_UI_SNAPSHOT_H
+#ifndef ANDROID_HWUI_SNAPSHOT_H
+#define ANDROID_HWUI_SNAPSHOT_H
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <utils/RefBase.h>
+#include <ui/Region.h>
#include <SkCanvas.h>
-#include <SkRegion.h>
#include "Layer.h"
#include "Matrix.h"
@@ -46,6 +46,7 @@ public:
Snapshot(): flags(0), previous(NULL), layer(NULL), fbo(0), invisible(false) {
transform = &mTransformRoot;
clipRect = &mClipRectRoot;
+ region = NULL;
}
/**
@@ -75,6 +76,13 @@ public:
} else {
flags |= Snapshot::kFlagDirtyLocalClip;
}
+
+ if (s->flags & Snapshot::kFlagFboTarget) {
+ flags |= Snapshot::kFlagFboTarget;
+ region = s->region;
+ } else {
+ region = NULL;
+ }
}
/**
@@ -105,6 +113,11 @@ public:
* Indicates that this snapshot has changed the ortho matrix.
*/
kFlagDirtyOrtho = 0x10,
+ /**
+ * Indicates that this snapshot or an ancestor snapshot is
+ * an FBO layer.
+ */
+ kFlagFboTarget = 0x20
};
/**
@@ -243,6 +256,11 @@ public:
*/
Rect* clipRect;
+ /**
+ * The ancestor layer's dirty region..
+ */
+ Region* region;
+
private:
mat4 mTransformRoot;
Rect mClipRectRoot;
@@ -253,4 +271,4 @@ private:
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_UI_SNAPSHOT_H
+#endif // ANDROID_HWUI_SNAPSHOT_H
diff --git a/libs/hwui/TextDropShadowCache.h b/libs/hwui/TextDropShadowCache.h
index 16e28146fdd7..adf09e20abb0 100644
--- a/libs/hwui/TextDropShadowCache.h
+++ b/libs/hwui/TextDropShadowCache.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_TEXT_DROP_SHADOW_CACHE_H
-#define ANDROID_UI_TEXT_DROP_SHADOW_CACHE_H
+#ifndef ANDROID_HWUI_TEXT_DROP_SHADOW_CACHE_H
+#define ANDROID_HWUI_TEXT_DROP_SHADOW_CACHE_H
#include <GLES2/gl2.h>
@@ -148,4 +148,4 @@ private:
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_UI_TEXT_DROP_SHADOW_CACHE_H
+#endif // ANDROID_HWUI_TEXT_DROP_SHADOW_CACHE_H
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index 755074d674f6..4922bb311878 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_TEXTURE_H
-#define ANDROID_UI_TEXTURE_H
+#ifndef ANDROID_HWUI_TEXTURE_H
+#define ANDROID_HWUI_TEXTURE_H
#include <GLES2/gl2.h>
@@ -86,4 +86,4 @@ private:
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_UI_TEXTURE_H
+#endif // ANDROID_HWUI_TEXTURE_H
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index d860953bc247..0c7948f70f98 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -200,9 +200,13 @@ void TextureCache::generateTexture(SkBitmap* bitmap, Texture* texture, bool rege
texture->blend = !bitmap->isOpaque();
break;
case SkBitmap::kIndex8_Config:
- uploadPalettedTexture(resize, bitmap, texture->width, texture->height);
+ uploadLoFiTexture(resize, bitmap, texture->width, texture->height);
texture->blend = false;
break;
+ case SkBitmap::kARGB_4444_Config:
+ uploadLoFiTexture(resize, bitmap, texture->width, texture->height);
+ texture->blend = true;
+ break;
default:
LOGW("Unsupported bitmap config: %d", bitmap->getConfig());
break;
@@ -215,7 +219,7 @@ void TextureCache::generateTexture(SkBitmap* bitmap, Texture* texture, bool rege
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
-void TextureCache::uploadPalettedTexture(bool resize, SkBitmap* bitmap,
+void TextureCache::uploadLoFiTexture(bool resize, SkBitmap* bitmap,
uint32_t width, uint32_t height) {
SkBitmap rgbaBitmap;
rgbaBitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index 671859716d82..d9d2387fd56a 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_TEXTURE_CACHE_H
-#define ANDROID_UI_TEXTURE_CACHE_H
+#ifndef ANDROID_HWUI_TEXTURE_CACHE_H
+#define ANDROID_HWUI_TEXTURE_CACHE_H
#include <SkBitmap.h>
@@ -93,7 +93,7 @@ private:
*/
void generateTexture(SkBitmap* bitmap, Texture* texture, bool regenerate = false);
- void uploadPalettedTexture(bool resize, SkBitmap* bitmap, uint32_t width, uint32_t height);
+ void uploadLoFiTexture(bool resize, SkBitmap* bitmap, uint32_t width, uint32_t height);
void uploadToTexture(bool resize, GLenum format, GLsizei width, GLsizei height,
GLenum type, const GLvoid * data);
@@ -115,4 +115,4 @@ private:
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_UI_TEXTURE_CACHE_H
+#endif // ANDROID_HWUI_TEXTURE_CACHE_H
diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h
index 1f540864f17f..bbf4d4af579c 100644
--- a/libs/hwui/Vertex.h
+++ b/libs/hwui/Vertex.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_VERTEX_H
-#define ANDROID_UI_VERTEX_H
+#ifndef ANDROID_HWUI_VERTEX_H
+#define ANDROID_HWUI_VERTEX_H
namespace android {
namespace uirenderer {
@@ -43,4 +43,4 @@ struct TextureVertex {
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_UI_VERTEX_H
+#endif // ANDROID_HWUI_VERTEX_H
diff --git a/libs/hwui/utils/Compare.h b/libs/hwui/utils/Compare.h
index 5ea0fc94ad77..6531e78ea108 100644
--- a/libs/hwui/utils/Compare.h
+++ b/libs/hwui/utils/Compare.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_COMPARE_H
-#define ANDROID_UI_COMPARE_H
+#ifndef ANDROID_HWUI_COMPARE_H
+#define ANDROID_HWUI_COMPARE_H
#include <cmath>
@@ -37,4 +37,4 @@
if (a < rhs.a) return true; \
if (a == rhs.a)
-#endif // ANDROID_UI_COMPARE_H
+#endif // ANDROID_HWUI_COMPARE_H
diff --git a/libs/hwui/utils/GenerationCache.h b/libs/hwui/utils/GenerationCache.h
index 5cea30fcdd79..2e7623602fcc 100644
--- a/libs/hwui/utils/GenerationCache.h
+++ b/libs/hwui/utils/GenerationCache.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_GENERATION_CACHE_H
-#define ANDROID_UI_GENERATION_CACHE_H
+#ifndef ANDROID_HWUI_GENERATION_CACHE_H
+#define ANDROID_HWUI_GENERATION_CACHE_H
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
@@ -242,4 +242,4 @@ void GenerationCache<K, V>::detachFromCache(sp<Entry<K, V> > entry) {
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_UI_GENERATION_CACHE_H
+#endif // ANDROID_HWUI_GENERATION_CACHE_H
diff --git a/libs/hwui/utils/SortedList.h b/libs/hwui/utils/SortedList.h
index 68f5e9dc47be..2fa890a39f73 100644
--- a/libs/hwui/utils/SortedList.h
+++ b/libs/hwui/utils/SortedList.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_SORTED_LIST_H
-#define ANDROID_UI_SORTED_LIST_H
+#ifndef ANDROID_HWUI_SORTED_LIST_H
+#define ANDROID_HWUI_SORTED_LIST_H
#include <stdint.h>
#include <sys/types.h>
@@ -239,4 +239,4 @@ int SortedList<TYPE>::do_compare(const void* lhs, const void* rhs) const {
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_UI_SORTED_LIST_H
+#endif // ANDROID_HWUI_SORTED_LIST_H
diff --git a/libs/hwui/utils/SortedListImpl.h b/libs/hwui/utils/SortedListImpl.h
index 7da09efcc67c..dc385b5f7b3a 100644
--- a/libs/hwui/utils/SortedListImpl.h
+++ b/libs/hwui/utils/SortedListImpl.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_SORTED_LIST_IMPL_H
-#define ANDROID_UI_SORTED_LIST_IMPL_H
+#ifndef ANDROID_HWUI_SORTED_LIST_IMPL_H
+#define ANDROID_HWUI_SORTED_LIST_IMPL_H
#include <utils/VectorImpl.h>
@@ -62,4 +62,4 @@ private:
}; // namespace uirenderer
}; // namespace android
-#endif // ANDROID_UI_SORTED_LIST_IMPL_H
+#endif // ANDROID_HWUI_SORTED_LIST_IMPL_H
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index 12db90885c4b..1994f6a4325f 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -289,7 +289,7 @@ private:
void flushSpan() {
bool merge = false;
if (tail-head == ssize_t(span.size())) {
- Rect const* p = cur;
+ Rect const* p = span.editArray();
Rect const* q = head;
if (p->top == q->bottom) {
merge = true;