diff options
author | 2012-02-16 19:24:51 -0800 | |
---|---|---|
committer | 2012-02-17 13:10:00 -0800 | |
commit | 33f6beb10f98e8ba96250e284876d607055d278d (patch) | |
tree | 215fc7d5624b6b41a018374f5d19f7dac84cf72b | |
parent | 445c83c7755fae179cf3328e89307e2775e97a5e (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.java | 9 | ||||
-rw-r--r-- | core/java/android/view/GLES20Canvas.java | 9 | ||||
-rw-r--r-- | core/java/android/view/GLES20RecordingCanvas.java | 4 | ||||
-rw-r--r-- | core/java/android/view/HardwareCanvas.java | 5 | ||||
-rw-r--r-- | core/java/android/view/HardwareRenderer.java | 3 | ||||
-rw-r--r-- | core/java/android/view/View.java | 2 | ||||
-rw-r--r-- | core/java/android/view/ViewGroup.java | 5 | ||||
-rw-r--r-- | core/java/android/widget/TextView.java | 8 | ||||
-rw-r--r-- | core/jni/android_view_GLES20Canvas.cpp | 6 | ||||
-rw-r--r-- | libs/hwui/DisplayListRenderer.cpp | 164 | ||||
-rw-r--r-- | libs/hwui/DisplayListRenderer.h | 61 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 8 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.h | 2 | ||||
-rw-r--r-- | libs/hwui/PathCache.cpp | 20 | ||||
-rw-r--r-- | libs/hwui/ShapeCache.h | 20 |
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); |