summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Romain Guy <romainguy@google.com> 2012-02-16 19:24:51 -0800
committer Romain Guy <romainguy@google.com> 2012-02-17 13:10:00 -0800
commit33f6beb10f98e8ba96250e284876d607055d278d (patch)
tree215fc7d5624b6b41a018374f5d19f7dac84cf72b
parent445c83c7755fae179cf3328e89307e2775e97a5e (diff)
Record possible clip rejects when recording display lists
This optimization allows us to quickly skip operations that lie entirely outside of the known bounds of a display list. Because of ViewGroup.setClipChildren, we must keep the operations recorded in the display list. setClipChildren(false) is however a very uncommon operation and we will therefore often benefit from this new optimization. Change-Id: I0942c864e55298e6dccd9977d15adefbce3ba3ad
-rw-r--r--core/java/android/view/DisplayList.java9
-rw-r--r--core/java/android/view/GLES20Canvas.java9
-rw-r--r--core/java/android/view/GLES20RecordingCanvas.java4
-rw-r--r--core/java/android/view/HardwareCanvas.java5
-rw-r--r--core/java/android/view/HardwareRenderer.java3
-rw-r--r--core/java/android/view/View.java2
-rw-r--r--core/java/android/view/ViewGroup.java5
-rw-r--r--core/java/android/widget/TextView.java8
-rw-r--r--core/jni/android_view_GLES20Canvas.cpp6
-rw-r--r--libs/hwui/DisplayListRenderer.cpp164
-rw-r--r--libs/hwui/DisplayListRenderer.h61
-rw-r--r--libs/hwui/OpenGLRenderer.cpp8
-rw-r--r--libs/hwui/OpenGLRenderer.h2
-rw-r--r--libs/hwui/PathCache.cpp20
-rw-r--r--libs/hwui/ShapeCache.h20
15 files changed, 236 insertions, 90 deletions
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
index fec0d4b94e8f..f60c8f0f5f54 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -27,6 +27,15 @@ package android.view;
*/
public abstract class DisplayList {
/**
+ * Flag used when calling
+ * {@link HardwareCanvas#drawDisplayList(DisplayList, int, int, android.graphics.Rect, int)}.
+ * When this flag is set, draw operations lying outside of the bounds of the
+ * display list will be culled early. It is recommeneded to always set this
+ * flag.
+ */
+ public static final int FLAG_CLIP_CHILDREN = 0x1;
+
+ /**
* Starts recording the display list. All operations performed on the
* returned canvas are recorded and stored in this display list.
*
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 4af5f3dd6b60..f5fc708c0c9c 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -385,13 +385,14 @@ class GLES20Canvas extends HardwareCanvas {
private static native void nSetDisplayListName(int displayList, String name);
@Override
- public boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty) {
- return nDrawDisplayList(mRenderer,
- ((GLES20DisplayList) displayList).getNativeDisplayList(), width, height, dirty);
+ public boolean drawDisplayList(DisplayList displayList, int width, int height,
+ Rect dirty, int flags) {
+ return nDrawDisplayList(mRenderer, ((GLES20DisplayList) displayList).getNativeDisplayList(),
+ width, height, dirty, flags);
}
private static native boolean nDrawDisplayList(int renderer, int displayList,
- int width, int height, Rect dirty);
+ int width, int height, Rect dirty, int flags);
@Override
void outputDisplayList(DisplayList displayList) {
diff --git a/core/java/android/view/GLES20RecordingCanvas.java b/core/java/android/view/GLES20RecordingCanvas.java
index c987f487d30b..c9ba65f3ab40 100644
--- a/core/java/android/view/GLES20RecordingCanvas.java
+++ b/core/java/android/view/GLES20RecordingCanvas.java
@@ -143,8 +143,8 @@ class GLES20RecordingCanvas extends GLES20Canvas implements Poolable<GLES20Recor
@Override
public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
int vertOffset, int[] colors, int colorOffset, Paint paint) {
- super.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset, colors, colorOffset,
- paint);
+ super.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset,
+ colors, colorOffset, paint);
mDisplayList.mBitmaps.add(bitmap);
// Shaders in the Paint are ignored when drawing a Bitmap
}
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index cbdbbde45b70..838c03c96dd7 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -57,11 +57,14 @@ public abstract class HardwareCanvas extends Canvas {
* @param height The height of the display list.
* @param dirty The dirty region to redraw in the next pass, matters only
* if this method returns true, can be null.
+ * @param flags Optional flags about drawing, see {@link DisplayList} for
+ * the possible flags.
*
* @return True if the content of the display list requires another
* drawing pass (invalidate()), false otherwise
*/
- public abstract boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty);
+ public abstract boolean drawDisplayList(DisplayList displayList, int width, int height,
+ Rect dirty, int flags);
/**
* Outputs the specified display list to the log. This method exists for use by
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 67466a4f60b9..ec9586308568 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -969,7 +969,8 @@ public abstract class HardwareRenderer {
}
boolean invalidateNeeded = canvas.drawDisplayList(displayList,
- view.getWidth(), view.getHeight(), mRedrawClip);
+ view.getWidth(), view.getHeight(), mRedrawClip,
+ DisplayList.FLAG_CLIP_CHILDREN);
if (mProfileEnabled) {
long now = System.nanoTime();
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 613a766dfbac..e34af08c11b2 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -11204,7 +11204,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
} else {
mPrivateFlags &= ~DIRTY_MASK;
((HardwareCanvas) canvas).drawDisplayList(displayList,
- mRight - mLeft, mBottom - mTop, null);
+ mRight - mLeft, mBottom - mTop, null, flags);
}
}
} else if (cache != null) {
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index d40d8af88ec6..ef2e1e71728c 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -168,6 +168,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
*/
protected int mGroupFlags;
+ /**
+ * NOTE: If you change the flags below make sure to reflect the changes
+ * the DisplayList class
+ */
+
// When set, ViewGroup invalidates only the child's rectangle
// Set by default
static final int FLAG_CLIP_CHILDREN = 0x1;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 7db8a1e6c99c..d29dc2e8eadb 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -5016,15 +5016,19 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
hardwareCanvas.setViewport(width, height);
// The dirty rect should always be null for a display list
hardwareCanvas.onPreDraw(null);
+ hardwareCanvas.translate(-mScrollX, -mScrollY);
layout.draw(hardwareCanvas, highlight, mHighlightPaint, cursorOffsetVertical);
+ hardwareCanvas.translate(mScrollX, mScrollY);
} finally {
hardwareCanvas.onPostDraw();
mTextDisplayList.end();
mTextDisplayListIsValid = true;
}
}
- ((HardwareCanvas) canvas).drawDisplayList(mTextDisplayList,
- mScrollX + width, mScrollY + height, null);
+ canvas.translate(mScrollX, mScrollY);
+ ((HardwareCanvas) canvas).drawDisplayList(mTextDisplayList, width, height, null,
+ DisplayList.FLAG_CLIP_CHILDREN);
+ canvas.translate(-mScrollX, -mScrollY);
} else {
layout.draw(canvas, highlight, mHighlightPaint, cursorOffsetVertical);
}
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index e19bb38dc53d..0c93b8344e98 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -652,9 +652,9 @@ static void android_view_GLES20Canvas_destroyDisplayList(JNIEnv* env,
static bool android_view_GLES20Canvas_drawDisplayList(JNIEnv* env,
jobject clazz, OpenGLRenderer* renderer, DisplayList* displayList,
- jint width, jint height, jobject dirty) {
+ jint width, jint height, jobject dirty, jint flags) {
android::uirenderer::Rect bounds;
- bool redraw = renderer->drawDisplayList(displayList, width, height, bounds);
+ bool redraw = renderer->drawDisplayList(displayList, width, height, bounds, flags);
if (redraw && dirty != NULL) {
env->CallVoidMethod(dirty, gRectClassInfo.set,
int(bounds.left), int(bounds.top), int(bounds.right), int(bounds.bottom));
@@ -901,7 +901,7 @@ static JNINativeMethod gMethods[] = {
{ "nGetDisplayListSize", "(I)I", (void*) android_view_GLES20Canvas_getDisplayListSize },
{ "nSetDisplayListName", "(ILjava/lang/String;)V",
(void*) android_view_GLES20Canvas_setDisplayListName },
- { "nDrawDisplayList", "(IIIILandroid/graphics/Rect;)Z",
+ { "nDrawDisplayList", "(IIIILandroid/graphics/Rect;I)Z",
(void*) android_view_GLES20Canvas_drawDisplayList },
{ "nCreateDisplayListRenderer", "()I", (void*) android_view_GLES20Canvas_createDisplayListRenderer },
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 1a11fbcfad68..f9088aca3718 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -226,6 +226,11 @@ void DisplayList::output(OpenGLRenderer& renderer, uint32_t level) {
while (!mReader.eof()) {
int op = mReader.readInt();
+ if (op & OP_MAY_BE_SKIPPED_MASK) {
+ int skip = mReader.readInt();
+ ALOGD("%sSkip %d", (char*) indent, skip);
+ op &= ~OP_MAY_BE_SKIPPED_MASK;
+ }
switch (op) {
case DrawGLFunction: {
@@ -316,8 +321,9 @@ void DisplayList::output(OpenGLRenderer& renderer, uint32_t level) {
DisplayList* displayList = getDisplayList();
uint32_t width = getUInt();
uint32_t height = getUInt();
- ALOGD("%s%s %p, %dx%d, %d", (char*) indent, OP_NAMES[op],
- displayList, width, height, level + 1);
+ int32_t flags = getInt();
+ ALOGD("%s%s %p, %dx%d, 0x%x %d", (char*) indent, OP_NAMES[op],
+ displayList, width, height, flags, level + 1);
renderer.outputDisplayList(displayList, level + 1);
}
break;
@@ -551,7 +557,7 @@ void DisplayList::output(OpenGLRenderer& renderer, uint32_t level) {
* in the output() function, since that function processes the same list of opcodes for the
* purposes of logging display list info for a given view.
*/
-bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) {
+bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level) {
bool needsInvalidate = false;
TextContainer text;
mReader.rewind();
@@ -572,6 +578,18 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level)
int saveCount = renderer.getSaveCount() - 1;
while (!mReader.eof()) {
int op = mReader.readInt();
+ if (op & OP_MAY_BE_SKIPPED_MASK) {
+ int32_t skip = mReader.readInt() * 4;
+ if (CC_LIKELY(flags & kReplayFlag_ClipChildren)) {
+ mReader.skip(skip);
+ DISPLAY_LIST_LOGD("%s%s skipping %d bytes", (char*) indent,
+ OP_NAMES[op & ~OP_MAY_BE_SKIPPED_MASK], skip);
+ continue;
+ } else {
+ op &= ~OP_MAY_BE_SKIPPED_MASK;
+ ALOGD("%s", OP_NAMES[op]);
+ }
+ }
logBuffer.writeCommand(level, op);
switch (op) {
@@ -584,7 +602,7 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level)
}
break;
case Save: {
- int rendererNum = getInt();
+ int32_t rendererNum = getInt();
DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, OP_NAMES[op], rendererNum);
renderer.save(rendererNum);
}
@@ -595,7 +613,7 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level)
}
break;
case RestoreToCount: {
- int restoreCount = saveCount + getInt();
+ int32_t restoreCount = saveCount + getInt();
DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, OP_NAMES[op], restoreCount);
renderer.restoreToCount(restoreCount);
}
@@ -606,7 +624,7 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level)
float f3 = getFloat();
float f4 = getFloat();
SkPaint* paint = getPaint(renderer);
- int flags = getInt();
+ int32_t flags = getInt();
DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p, 0x%x", (char*) indent,
OP_NAMES[op], f1, f2, f3, f4, paint, flags);
renderer.saveLayer(f1, f2, f3, f4, paint, flags);
@@ -617,8 +635,8 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level)
float f2 = getFloat();
float f3 = getFloat();
float f4 = getFloat();
- int alpha = getInt();
- int flags = getInt();
+ int32_t alpha = getInt();
+ int32_t flags = getInt();
DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", (char*) indent,
OP_NAMES[op], f1, f2, f3, f4, alpha, flags);
renderer.saveLayerAlpha(f1, f2, f3, f4, alpha, flags);
@@ -668,7 +686,7 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level)
float f2 = getFloat();
float f3 = getFloat();
float f4 = getFloat();
- int regionOp = getInt();
+ int32_t regionOp = getInt();
DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d", (char*) indent, OP_NAMES[op],
f1, f2, f3, f4, regionOp);
renderer.clipRect(f1, f2, f3, f4, (SkRegion::Op) regionOp);
@@ -678,10 +696,11 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level)
DisplayList* displayList = getDisplayList();
uint32_t width = getUInt();
uint32_t height = getUInt();
- DISPLAY_LIST_LOGD("%s%s %p, %dx%d, %d", (char*) indent, OP_NAMES[op],
- displayList, width, height, level + 1);
+ int32_t flags = getInt();
+ DISPLAY_LIST_LOGD("%s%s %p, %dx%d, 0x%x %d", (char*) indent, OP_NAMES[op],
+ displayList, width, height, flags, level + 1);
needsInvalidate |= renderer.drawDisplayList(displayList, width, height,
- dirty, level + 1);
+ dirty, flags, level + 1);
}
break;
case DrawLayer: {
@@ -730,7 +749,7 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level)
}
break;
case DrawBitmapMesh: {
- int verticesCount = 0;
+ int32_t verticesCount = 0;
uint32_t colorsCount = 0;
SkBitmap* bitmap = getBitmap();
@@ -738,7 +757,7 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level)
uint32_t meshHeight = getInt();
float* vertices = getFloats(verticesCount);
bool hasColors = getInt();
- int* colors = hasColors ? getInts(colorsCount) : NULL;
+ int32_t* colors = hasColors ? getInts(colorsCount) : NULL;
SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
@@ -771,8 +790,8 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level)
}
break;
case DrawColor: {
- int color = getInt();
- int xferMode = getInt();
+ int32_t color = getInt();
+ int32_t xferMode = getInt();
DISPLAY_LIST_LOGD("%s%s 0x%x %d", (char*) indent, OP_NAMES[op], color, xferMode);
renderer.drawColor(color, (SkXfermode::Mode) xferMode);
}
@@ -829,7 +848,7 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level)
float f4 = getFloat();
float f5 = getFloat();
float f6 = getFloat();
- int i1 = getInt();
+ int32_t i1 = getInt();
SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d, %p",
(char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, i1, paint);
@@ -844,7 +863,7 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level)
}
break;
case DrawLines: {
- int count = 0;
+ int32_t count = 0;
float* points = getFloats(count);
SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
@@ -852,7 +871,7 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level)
}
break;
case DrawPoints: {
- int count = 0;
+ int32_t count = 0;
float* points = getFloats(count);
SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
@@ -861,7 +880,7 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level)
break;
case DrawText: {
getText(&text);
- int count = getInt();
+ int32_t count = getInt();
float x = getFloat();
float y = getFloat();
SkPaint* paint = getPaint(renderer);
@@ -873,8 +892,8 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level)
break;
case DrawPosText: {
getText(&text);
- int count = getInt();
- int positionsCount = 0;
+ int32_t count = getInt();
+ int32_t positionsCount = 0;
float* positions = getFloats(positionsCount);
SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s %s, %d, %d, %p", (char*) indent,
@@ -913,7 +932,7 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level)
float radius = getFloat();
float dx = getFloat();
float dy = getFloat();
- int color = getInt();
+ int32_t color = getInt();
DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, 0x%x", (char*) indent, OP_NAMES[op],
radius, dx, dy, color);
renderer.setupShadow(radius, dx, dy, color);
@@ -925,8 +944,8 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level)
}
break;
case SetupPaintFilter: {
- int clearBits = getInt();
- int setBits = getInt();
+ int32_t clearBits = getInt();
+ int32_t setBits = getInt();
DISPLAY_LIST_LOGD("%s%s 0x%x, 0x%x", (char*) indent, OP_NAMES[op],
clearBits, setBits);
renderer.setupPaintFilter(clearBits, setBits);
@@ -949,7 +968,8 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level)
// Base structure
///////////////////////////////////////////////////////////////////////////////
-DisplayListRenderer::DisplayListRenderer(): mWriter(MIN_WRITER_SIZE), mHasDrawOps(false) {
+DisplayListRenderer::DisplayListRenderer(): mWriter(MIN_WRITER_SIZE),
+ mTranslateX(0.0f), mTranslateY(0.0f), mHasTranslate(false), mHasDrawOps(false) {
}
DisplayListRenderer::~DisplayListRenderer() {
@@ -1019,6 +1039,7 @@ void DisplayListRenderer::prepareDirty(float left, float top,
void DisplayListRenderer::finish() {
insertRestoreToCount();
+ insertTranlate();
OpenGLRenderer::finish();
}
@@ -1043,15 +1064,18 @@ int DisplayListRenderer::save(int flags) {
void DisplayListRenderer::restore() {
if (mRestoreSaveCount < 0) {
- addOp(DisplayList::Restore);
- } else {
- mRestoreSaveCount--;
+ restoreToCount(getSaveCount() - 1);
+ return;
}
+
+ mRestoreSaveCount--;
+ insertTranlate();
OpenGLRenderer::restore();
}
void DisplayListRenderer::restoreToCount(int saveCount) {
mRestoreSaveCount = saveCount;
+ insertTranlate();
OpenGLRenderer::restoreToCount(saveCount);
}
@@ -1074,8 +1098,10 @@ int DisplayListRenderer::saveLayerAlpha(float left, float top, float right, floa
}
void DisplayListRenderer::translate(float dx, float dy) {
- addOp(DisplayList::Translate);
- addPoint(dx, dy);
+ mHasTranslate = true;
+ mTranslateX += dx;
+ mTranslateY += dy;
+ insertRestoreToCount();
OpenGLRenderer::translate(dx, dy);
}
@@ -1118,12 +1144,15 @@ bool DisplayListRenderer::clipRect(float left, float top, float right, float bot
}
bool DisplayListRenderer::drawDisplayList(DisplayList* displayList,
- uint32_t width, uint32_t height, Rect& dirty, uint32_t level) {
+ uint32_t width, uint32_t height, Rect& dirty, int32_t flags, uint32_t level) {
// dirty is an out parameter and should not be recorded,
// it matters only when replaying the display list
- addOp(DisplayList::DrawDisplayList);
+ const bool reject = quickReject(0.0f, 0.0f, width, height);
+ uint32_t* location = addOp(DisplayList::DrawDisplayList, reject);
addDisplayList(displayList);
addSize(width, height);
+ addInt(flags);
+ addSkip(location);
return false;
}
@@ -1134,30 +1163,38 @@ void DisplayListRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* pai
addPaint(paint);
}
-void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float left, float top,
- SkPaint* paint) {
- addOp(DisplayList::DrawBitmap);
+void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint) {
+ const bool reject = quickReject(left, top, left + bitmap->width(), top + bitmap->height());
+ uint32_t* location = addOp(DisplayList::DrawBitmap, reject);
addBitmap(bitmap);
addPoint(left, top);
addPaint(paint);
+ addSkip(location);
}
-void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix,
- SkPaint* paint) {
- addOp(DisplayList::DrawBitmapMatrix);
+void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint) {
+ Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height());
+ const mat4 transform(*matrix);
+ transform.mapRect(r);
+
+ const bool reject = quickReject(r.left, r.top, r.right, r.bottom);
+ uint32_t* location = addOp(DisplayList::DrawBitmapMatrix, reject);
addBitmap(bitmap);
addMatrix(matrix);
addPaint(paint);
+ addSkip(location);
}
void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
float srcRight, float srcBottom, float dstLeft, float dstTop,
float dstRight, float dstBottom, SkPaint* paint) {
- addOp(DisplayList::DrawBitmapRect);
+ const bool reject = quickReject(dstLeft, dstTop, dstRight, dstBottom);
+ uint32_t* location = addOp(DisplayList::DrawBitmapRect, reject);
addBitmap(bitmap);
addBounds(srcLeft, srcTop, srcRight, srcBottom);
addBounds(dstLeft, dstTop, dstRight, dstBottom);
addPaint(paint);
+ addSkip(location);
}
void DisplayListRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight,
@@ -1179,13 +1216,15 @@ void DisplayListRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int me
void DisplayListRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
float left, float top, float right, float bottom, SkPaint* paint) {
- addOp(DisplayList::DrawPatch);
+ const bool reject = quickReject(left, top, right, bottom);
+ uint32_t* location = addOp(DisplayList::DrawPatch, reject);
addBitmap(bitmap);
addInts(xDivs, width);
addInts(yDivs, height);
addUInts(colors, numColors);
addBounds(left, top, right, bottom);
addPaint(paint);
+ addSkip(location);
}
void DisplayListRenderer::drawColor(int color, SkXfermode::Mode mode) {
@@ -1196,17 +1235,23 @@ void DisplayListRenderer::drawColor(int color, SkXfermode::Mode mode) {
void DisplayListRenderer::drawRect(float left, float top, float right, float bottom,
SkPaint* paint) {
- addOp(DisplayList::DrawRect);
+ const bool reject = paint->getStyle() == SkPaint::kFill_Style &&
+ quickReject(left, top, right, bottom);
+ uint32_t* location = addOp(DisplayList::DrawRect, reject);
addBounds(left, top, right, bottom);
addPaint(paint);
+ addSkip(location);
}
void DisplayListRenderer::drawRoundRect(float left, float top, float right, float bottom,
float rx, float ry, SkPaint* paint) {
- addOp(DisplayList::DrawRoundRect);
+ const bool reject = paint->getStyle() == SkPaint::kFill_Style &&
+ quickReject(left, top, right, bottom);
+ uint32_t* location = addOp(DisplayList::DrawRoundRect, reject);
addBounds(left, top, right, bottom);
addPoint(rx, ry);
addPaint(paint);
+ addSkip(location);
}
void DisplayListRenderer::drawCircle(float x, float y, float radius, SkPaint* paint) {
@@ -1233,9 +1278,15 @@ void DisplayListRenderer::drawArc(float left, float top, float right, float bott
}
void DisplayListRenderer::drawPath(SkPath* path, SkPaint* paint) {
- addOp(DisplayList::DrawPath);
+ float left, top, offset;
+ uint32_t width, height;
+ computePathBounds(path, paint, left, top, offset, width, height);
+
+ const bool reject = quickReject(left - offset, top - offset, width, height);
+ uint32_t* location = addOp(DisplayList::DrawPath, reject);
addPath(path);
addPaint(paint);
+ addSkip(location);
}
void DisplayListRenderer::drawLines(float* points, int count, SkPaint* paint) {
@@ -1252,11 +1303,8 @@ void DisplayListRenderer::drawPoints(float* points, int count, SkPaint* paint) {
void DisplayListRenderer::drawText(const char* text, int bytesCount, int count,
float x, float y, SkPaint* paint, float length) {
- if (count <= 0) return;
- addOp(DisplayList::DrawText);
- addText(text, bytesCount);
- addInt(count);
- addPoint(x, y);
+ if (!text || count <= 0) return;
+
// TODO: We should probably make a copy of the paint instead of modifying
// it; modifying the paint will change its generationID the first
// time, which might impact caches. More investigation needed to
@@ -1265,13 +1313,27 @@ void DisplayListRenderer::drawText(const char* text, int bytesCount, int count,
// its own copy as it does right now.
// Beware: this needs Glyph encoding (already done on the Paint constructor)
paint->setAntiAlias(true);
+ if (length < 0.0f) length = paint->measureText(text, bytesCount);
+
+ bool reject = false;
+ if (CC_LIKELY(paint->getTextAlign() == SkPaint::kLeft_Align)) {
+ SkPaint::FontMetrics metrics;
+ paint->getFontMetrics(&metrics, 0.0f);
+ reject = quickReject(x, y + metrics.fTop, x + length, y + metrics.fBottom);
+ }
+
+ uint32_t* location = addOp(DisplayList::DrawText, reject);
+ addText(text, bytesCount);
+ addInt(count);
+ addPoint(x, y);
addPaint(paint);
- addFloat(length < 0.0f ? paint->measureText(text, bytesCount) : length);
+ addFloat(length);
+ addSkip(location);
}
void DisplayListRenderer::drawPosText(const char* text, int bytesCount, int count,
const float* positions, SkPaint* paint) {
- if (count <= 0) return;
+ if (!text || count <= 0) return;
addOp(DisplayList::DrawPosText);
addText(text, bytesCount);
addInt(count);
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 46506e4e9a96..6dd47be991ac 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -42,6 +42,7 @@ namespace uirenderer {
///////////////////////////////////////////////////////////////////////////////
#define MIN_WRITER_SIZE 4096
+#define OP_MAY_BE_SKIPPED_MASK 0xff000000
// Debug
#if DEBUG_DISPLAY_LIST
@@ -110,13 +111,18 @@ public:
DrawGLFunction,
};
+ // See flags defined in DisplayList.java
+ enum ReplayFlag {
+ kReplayFlag_ClipChildren = 0x1
+ };
+
static const char* OP_NAMES[];
void initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing = false);
ANDROID_API size_t getSize();
- bool replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level = 0);
+ bool replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level = 0);
void output(OpenGLRenderer& renderer, uint32_t level = 0);
@@ -167,11 +173,11 @@ private:
return (SkiaColorFilter*) getInt();
}
- inline int getIndex() {
+ inline int32_t getIndex() {
return mReader.readInt();
}
- inline int getInt() {
+ inline int32_t getInt() {
return mReader.readInt();
}
@@ -209,7 +215,7 @@ private:
return (uint32_t*) mReader.skip(count * sizeof(uint32_t));
}
- float* getFloats(int& count) {
+ float* getFloats(int32_t& count) {
count = getInt();
return (float*) mReader.skip(count * sizeof(float));
}
@@ -279,7 +285,7 @@ public:
virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
virtual bool drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height,
- Rect& dirty, uint32_t level = 0);
+ Rect& dirty, int32_t flags, uint32_t level = 0);
virtual void drawLayer(Layer* layer, float x, float y, SkPaint* paint);
virtual void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
virtual void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
@@ -358,13 +364,45 @@ private:
}
}
- inline void addOp(DisplayList::Op drawOp) {
+ void insertTranlate() {
+ if (mHasTranslate) {
+ if (mTranslateX != 0.0f || mTranslateY != 0.0f) {
+ mWriter.writeInt(DisplayList::Translate);
+ addPoint(mTranslateX, mTranslateY);
+ mTranslateX = mTranslateY = 0.0f;
+ }
+ mHasTranslate = false;
+ }
+ }
+
+ inline void addOp(const DisplayList::Op drawOp) {
insertRestoreToCount();
+ insertTranlate();
mWriter.writeInt(drawOp);
mHasDrawOps = mHasDrawOps || drawOp >= DisplayList::DrawDisplayList;
}
- inline void addInt(int value) {
+ uint32_t* addOp(const DisplayList::Op drawOp, const bool reject) {
+ insertRestoreToCount();
+ insertTranlate();
+ mHasDrawOps = mHasDrawOps || drawOp >= DisplayList::DrawDisplayList;
+ if (reject) {
+ mWriter.writeInt(OP_MAY_BE_SKIPPED_MASK | drawOp);
+ mWriter.writeInt(0);
+ uint32_t* location = reject ? mWriter.peek32(mWriter.size() - 4) : NULL;
+ return location;
+ }
+ mWriter.writeInt(drawOp);
+ return NULL;
+ }
+
+ inline void addSkip(uint32_t* location) {
+ if (location) {
+ *location = (int32_t) (mWriter.peek32(mWriter.size() - 4) - location);
+ }
+ }
+
+ inline void addInt(int32_t value) {
mWriter.writeInt(value);
}
@@ -391,9 +429,9 @@ private:
mWriter.writeScalar(value);
}
- void addFloats(const float* values, int count) {
+ void addFloats(const float* values, int32_t count) {
mWriter.writeInt(count);
- for (int i = 0; i < count; i++) {
+ for (int32_t i = 0; i < count; i++) {
mWriter.writeScalar(values[i]);
}
}
@@ -513,6 +551,11 @@ private:
SkWriter32 mWriter;
int mRestoreSaveCount;
+
+ float mTranslateX;
+ float mTranslateY;
+ bool mHasTranslate;
+
bool mHasDrawOps;
friend class DisplayList;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index afae70fddb5d..55e2ca5d7f24 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1321,7 +1321,7 @@ void OpenGLRenderer::finishDrawTexture() {
///////////////////////////////////////////////////////////////////////////////
bool OpenGLRenderer::drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height,
- Rect& dirty, uint32_t level) {
+ Rect& dirty, int32_t flags, uint32_t level) {
if (quickReject(0.0f, 0.0f, width, height)) {
return false;
}
@@ -1329,7 +1329,7 @@ bool OpenGLRenderer::drawDisplayList(DisplayList* displayList, uint32_t width, u
// All the usual checks and setup operations (quickReject, setupDraw, etc.)
// will be performed by the display list itself
if (displayList && displayList->isRenderable()) {
- return displayList->replay(*this, dirty, level);
+ return displayList->replay(*this, dirty, flags, level);
}
return false;
@@ -2189,8 +2189,7 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
SkPaint::FontMetrics metrics;
paint->getFontMetrics(&metrics, 0.0f);
// If no length was specified, just perform the hit test on the Y axis
- if (quickReject(x, y + metrics.fTop,
- x + (length >= 0.0f ? length : INT_MAX / 2), y + metrics.fBottom)) {
+ if (quickReject(x, y + metrics.fTop, x + length, y + metrics.fBottom)) {
return;
}
@@ -2298,6 +2297,7 @@ void OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) {
mCaches.activeTexture(0);
+ // TODO: Perform early clip test before we rasterize the path
const PathTexture* texture = mCaches.pathCache.get(path, paint);
if (!texture) return;
const AutoTexture autoCleanup(texture);
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 3c2d09e81769..3f63c3fe11a1 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -98,7 +98,7 @@ public:
virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
virtual bool drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height,
- Rect& dirty, uint32_t level = 0);
+ Rect& dirty, int32_t flags, uint32_t level = 0);
virtual void outputDisplayList(DisplayList* displayList, uint32_t level = 0);
virtual void drawLayer(Layer* layer, float x, float y, SkPaint* paint);
virtual void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index e893f7a95adb..e09c24381d9d 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -24,6 +24,23 @@
namespace android {
namespace uirenderer {
+// Defined in ShapeCache.h
+void computePathBounds(const SkPath *path, const SkPaint* paint,
+ float& left, float& top, float& offset, uint32_t& width, uint32_t& height) {
+ const SkRect& bounds = path->getBounds();
+
+ const float pathWidth = fmax(bounds.width(), 1.0f);
+ const float pathHeight = fmax(bounds.height(), 1.0f);
+
+ left = bounds.fLeft;
+ top = bounds.fTop;
+
+ offset = (int) floorf(fmax(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f);
+
+ width = uint32_t(pathWidth + offset * 2.0 + 0.5);
+ height = uint32_t(pathHeight + offset * 2.0 + 0.5);
+}
+
///////////////////////////////////////////////////////////////////////////////
// Path cache
///////////////////////////////////////////////////////////////////////////////
@@ -69,6 +86,9 @@ PathTexture* PathCache::get(SkPath* path, SkPaint* paint) {
PathCacheEntry entry(path, paint);
PathTexture* texture = mCache.get(entry);
+ float left, top, offset;
+ uint32_t width, height;
+
if (!texture) {
texture = addTexture(entry, path, paint);
} else if (path->getGenerationID() != texture->generation) {
diff --git a/libs/hwui/ShapeCache.h b/libs/hwui/ShapeCache.h
index 30ce69081244..f180e942adc6 100644
--- a/libs/hwui/ShapeCache.h
+++ b/libs/hwui/ShapeCache.h
@@ -489,18 +489,16 @@ void ShapeCache<Entry>::removeTexture(PathTexture* texture) {
}
}
+void computePathBounds(const SkPath *path, const SkPaint* paint,
+ float& left, float& top, float& offset, uint32_t& width, uint32_t& height);
+
template<class Entry>
PathTexture* ShapeCache<Entry>::addTexture(const Entry& entry, const SkPath *path,
const SkPaint* paint) {
- const SkRect& bounds = path->getBounds();
-
- const float pathWidth = fmax(bounds.width(), 1.0f);
- const float pathHeight = fmax(bounds.height(), 1.0f);
-
- const float offset = (int) floorf(fmax(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f);
- const uint32_t width = uint32_t(pathWidth + offset * 2.0 + 0.5);
- const uint32_t height = uint32_t(pathHeight + offset * 2.0 + 0.5);
+ float left, top, offset;
+ uint32_t width, height;
+ computePathBounds(path, paint, left, top, offset, width, height);
if (width > mMaxTextureSize || height > mMaxTextureSize) {
ALOGW("Shape %s too large to be rendered into a texture (%dx%d, max=%dx%d)",
@@ -517,8 +515,8 @@ PathTexture* ShapeCache<Entry>::addTexture(const Entry& entry, const SkPath *pat
}
PathTexture* texture = new PathTexture;
- texture->left = bounds.fLeft;
- texture->top = bounds.fTop;
+ texture->left = left;
+ texture->top = top;
texture->offset = offset;
texture->width = width;
texture->height = height;
@@ -542,7 +540,7 @@ PathTexture* ShapeCache<Entry>::addTexture(const Entry& entry, const SkPath *pat
SkSafeUnref(pathPaint.setXfermode(mode));
SkCanvas canvas(bitmap);
- canvas.translate(-bounds.fLeft + offset, -bounds.fTop + offset);
+ canvas.translate(-left + offset, -top + offset);
canvas.drawPath(*path, pathPaint);
generateTexture(bitmap, texture);