Merge changes Ie0773f85,Ie5e75505
* changes:
Even FASTER damage calculations!
Have all the setters return changed
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index 6acb134..b5b9199 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -217,8 +217,6 @@
private static native void nUpdateRenderLayer(long layerUpdater, long displayList,
int left, int top, int right, int bottom);
- private static native boolean nFlushChanges(long layerUpdater);
-
private static native long nGetLayer(long layerUpdater);
private static native int nGetTexName(long layerUpdater);
}
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index d67c974..592dec8 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -363,8 +363,7 @@
* @param callbacks Callbacks invoked when drawing happens.
* @param dirty The dirty rectangle to update, can be null.
*/
- abstract void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
- Rect dirty);
+ abstract void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks);
/**
* Creates a new hardware layer. A hardware layer built by calling this
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index e63829e..4631b64 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -325,8 +325,8 @@
*
* @hide
*/
- public void setCaching(boolean caching) {
- nSetCaching(mNativeRenderNode, caching);
+ public boolean setCaching(boolean caching) {
+ return nSetCaching(mNativeRenderNode, caching);
}
/**
@@ -335,8 +335,8 @@
*
* @param clipToBounds true if the display list should clip to its bounds
*/
- public void setClipToBounds(boolean clipToBounds) {
- nSetClipToBounds(mNativeRenderNode, clipToBounds);
+ public boolean setClipToBounds(boolean clipToBounds) {
+ return nSetClipToBounds(mNativeRenderNode, clipToBounds);
}
/**
@@ -346,8 +346,8 @@
* @param shouldProject true if the display list should be projected onto a
* containing volume.
*/
- public void setProjectBackwards(boolean shouldProject) {
- nSetProjectBackwards(mNativeRenderNode, shouldProject);
+ public boolean setProjectBackwards(boolean shouldProject) {
+ return nSetProjectBackwards(mNativeRenderNode, shouldProject);
}
/**
@@ -355,8 +355,8 @@
* DisplayList should draw any descendent DisplayLists with
* ProjectBackwards=true directly on top of it. Default value is false.
*/
- public void setProjectionReceiver(boolean shouldRecieve) {
- nSetProjectionReceiver(mNativeRenderNode, shouldRecieve);
+ public boolean setProjectionReceiver(boolean shouldRecieve) {
+ return nSetProjectionReceiver(mNativeRenderNode, shouldRecieve);
}
/**
@@ -365,15 +365,16 @@
*
* Deep copies the data into native to simplify reference ownership.
*/
- public void setOutline(Outline outline) {
+ public boolean setOutline(Outline outline) {
if (outline == null || outline.isEmpty()) {
- nSetOutlineEmpty(mNativeRenderNode);
+ return nSetOutlineEmpty(mNativeRenderNode);
} else if (outline.mRect != null) {
- nSetOutlineRoundRect(mNativeRenderNode, outline.mRect.left, outline.mRect.top,
+ return nSetOutlineRoundRect(mNativeRenderNode, outline.mRect.left, outline.mRect.top,
outline.mRect.right, outline.mRect.bottom, outline.mRadius);
} else if (outline.mPath != null) {
- nSetOutlineConvexPath(mNativeRenderNode, outline.mPath.mNativePath);
+ return nSetOutlineConvexPath(mNativeRenderNode, outline.mPath.mNativePath);
}
+ throw new IllegalArgumentException("Unrecognized outline?");
}
/**
@@ -381,8 +382,8 @@
*
* @param clipToOutline true if clipping to the outline.
*/
- public void setClipToOutline(boolean clipToOutline) {
- nSetClipToOutline(mNativeRenderNode, clipToOutline);
+ public boolean setClipToOutline(boolean clipToOutline) {
+ return nSetClipToOutline(mNativeRenderNode, clipToOutline);
}
public boolean getClipToOutline() {
@@ -392,9 +393,9 @@
/**
* Controls the RenderNode's circular reveal clip.
*/
- public void setRevealClip(boolean shouldClip, boolean inverseClip,
+ public boolean setRevealClip(boolean shouldClip, boolean inverseClip,
float x, float y, float radius) {
- nSetRevealClip(mNativeRenderNode, shouldClip, inverseClip, x, y, radius);
+ return nSetRevealClip(mNativeRenderNode, shouldClip, inverseClip, x, y, radius);
}
/**
@@ -403,8 +404,8 @@
*
* @param matrix A transform matrix to apply to this display list
*/
- public void setStaticMatrix(Matrix matrix) {
- nSetStaticMatrix(mNativeRenderNode, matrix.native_instance);
+ public boolean setStaticMatrix(Matrix matrix) {
+ return nSetStaticMatrix(mNativeRenderNode, matrix.native_instance);
}
/**
@@ -417,8 +418,8 @@
*
* @hide
*/
- public void setAnimationMatrix(Matrix matrix) {
- nSetAnimationMatrix(mNativeRenderNode,
+ public boolean setAnimationMatrix(Matrix matrix) {
+ return nSetAnimationMatrix(mNativeRenderNode,
(matrix != null) ? matrix.native_instance : 0);
}
@@ -430,8 +431,8 @@
* @see View#setAlpha(float)
* @see #getAlpha()
*/
- public void setAlpha(float alpha) {
- nSetAlpha(mNativeRenderNode, alpha);
+ public boolean setAlpha(float alpha) {
+ return nSetAlpha(mNativeRenderNode, alpha);
}
/**
@@ -456,8 +457,8 @@
* @see android.view.View#hasOverlappingRendering()
* @see #hasOverlappingRendering()
*/
- public void setHasOverlappingRendering(boolean hasOverlappingRendering) {
- nSetHasOverlappingRendering(mNativeRenderNode, hasOverlappingRendering);
+ public boolean setHasOverlappingRendering(boolean hasOverlappingRendering) {
+ return nSetHasOverlappingRendering(mNativeRenderNode, hasOverlappingRendering);
}
/**
@@ -472,8 +473,8 @@
return nHasOverlappingRendering(mNativeRenderNode);
}
- public void setElevation(float lift) {
- nSetElevation(mNativeRenderNode, lift);
+ public boolean setElevation(float lift) {
+ return nSetElevation(mNativeRenderNode, lift);
}
public float getElevation() {
@@ -488,8 +489,8 @@
* @see View#setTranslationX(float)
* @see #getTranslationX()
*/
- public void setTranslationX(float translationX) {
- nSetTranslationX(mNativeRenderNode, translationX);
+ public boolean setTranslationX(float translationX) {
+ return nSetTranslationX(mNativeRenderNode, translationX);
}
/**
@@ -509,8 +510,8 @@
* @see View#setTranslationY(float)
* @see #getTranslationY()
*/
- public void setTranslationY(float translationY) {
- nSetTranslationY(mNativeRenderNode, translationY);
+ public boolean setTranslationY(float translationY) {
+ return nSetTranslationY(mNativeRenderNode, translationY);
}
/**
@@ -528,8 +529,8 @@
* @see View#setTranslationZ(float)
* @see #getTranslationZ()
*/
- public void setTranslationZ(float translationZ) {
- nSetTranslationZ(mNativeRenderNode, translationZ);
+ public boolean setTranslationZ(float translationZ) {
+ return nSetTranslationZ(mNativeRenderNode, translationZ);
}
/**
@@ -549,8 +550,8 @@
* @see View#setRotation(float)
* @see #getRotation()
*/
- public void setRotation(float rotation) {
- nSetRotation(mNativeRenderNode, rotation);
+ public boolean setRotation(float rotation) {
+ return nSetRotation(mNativeRenderNode, rotation);
}
/**
@@ -570,8 +571,8 @@
* @see View#setRotationX(float)
* @see #getRotationX()
*/
- public void setRotationX(float rotationX) {
- nSetRotationX(mNativeRenderNode, rotationX);
+ public boolean setRotationX(float rotationX) {
+ return nSetRotationX(mNativeRenderNode, rotationX);
}
/**
@@ -591,8 +592,8 @@
* @see View#setRotationY(float)
* @see #getRotationY()
*/
- public void setRotationY(float rotationY) {
- nSetRotationY(mNativeRenderNode, rotationY);
+ public boolean setRotationY(float rotationY) {
+ return nSetRotationY(mNativeRenderNode, rotationY);
}
/**
@@ -612,8 +613,8 @@
* @see View#setScaleX(float)
* @see #getScaleX()
*/
- public void setScaleX(float scaleX) {
- nSetScaleX(mNativeRenderNode, scaleX);
+ public boolean setScaleX(float scaleX) {
+ return nSetScaleX(mNativeRenderNode, scaleX);
}
/**
@@ -633,8 +634,8 @@
* @see View#setScaleY(float)
* @see #getScaleY()
*/
- public void setScaleY(float scaleY) {
- nSetScaleY(mNativeRenderNode, scaleY);
+ public boolean setScaleY(float scaleY) {
+ return nSetScaleY(mNativeRenderNode, scaleY);
}
/**
@@ -654,8 +655,8 @@
* @see View#setPivotX(float)
* @see #getPivotX()
*/
- public void setPivotX(float pivotX) {
- nSetPivotX(mNativeRenderNode, pivotX);
+ public boolean setPivotX(float pivotX) {
+ return nSetPivotX(mNativeRenderNode, pivotX);
}
/**
@@ -675,8 +676,8 @@
* @see View#setPivotY(float)
* @see #getPivotY()
*/
- public void setPivotY(float pivotY) {
- nSetPivotY(mNativeRenderNode, pivotY);
+ public boolean setPivotY(float pivotY) {
+ return nSetPivotY(mNativeRenderNode, pivotY);
}
/**
@@ -702,8 +703,8 @@
* @see View#setCameraDistance(float)
* @see #getCameraDistance()
*/
- public void setCameraDistance(float distance) {
- nSetCameraDistance(mNativeRenderNode, distance);
+ public boolean setCameraDistance(float distance) {
+ return nSetCameraDistance(mNativeRenderNode, distance);
}
/**
@@ -723,8 +724,8 @@
* @see View#setLeft(int)
* @see #getLeft()
*/
- public void setLeft(int left) {
- nSetLeft(mNativeRenderNode, left);
+ public boolean setLeft(int left) {
+ return nSetLeft(mNativeRenderNode, left);
}
/**
@@ -744,8 +745,8 @@
* @see View#setTop(int)
* @see #getTop()
*/
- public void setTop(int top) {
- nSetTop(mNativeRenderNode, top);
+ public boolean setTop(int top) {
+ return nSetTop(mNativeRenderNode, top);
}
/**
@@ -765,8 +766,8 @@
* @see View#setRight(int)
* @see #getRight()
*/
- public void setRight(int right) {
- nSetRight(mNativeRenderNode, right);
+ public boolean setRight(int right) {
+ return nSetRight(mNativeRenderNode, right);
}
/**
@@ -786,8 +787,8 @@
* @see View#setBottom(int)
* @see #getBottom()
*/
- public void setBottom(int bottom) {
- nSetBottom(mNativeRenderNode, bottom);
+ public boolean setBottom(int bottom) {
+ return nSetBottom(mNativeRenderNode, bottom);
}
/**
@@ -812,8 +813,8 @@
* @see View#setRight(int)
* @see View#setBottom(int)
*/
- public void setLeftTopRightBottom(int left, int top, int right, int bottom) {
- nSetLeftTopRightBottom(mNativeRenderNode, left, top, right, bottom);
+ public boolean setLeftTopRightBottom(int left, int top, int right, int bottom) {
+ return nSetLeftTopRightBottom(mNativeRenderNode, left, top, right, bottom);
}
/**
@@ -824,8 +825,8 @@
*
* @see View#offsetLeftAndRight(int)
*/
- public void offsetLeftAndRight(float offset) {
- nOffsetLeftAndRight(mNativeRenderNode, offset);
+ public boolean offsetLeftAndRight(float offset) {
+ return nOffsetLeftAndRight(mNativeRenderNode, offset);
}
/**
@@ -836,8 +837,15 @@
*
* @see View#offsetTopAndBottom(int)
*/
- public void offsetTopAndBottom(float offset) {
- nOffsetTopAndBottom(mNativeRenderNode, offset);
+ public boolean offsetTopAndBottom(float offset) {
+ return nOffsetTopAndBottom(mNativeRenderNode, offset);
+ }
+
+ /**
+ * Sets the scroll position, this is used for damage calculations
+ */
+ public void setScrollPosition(int x, int y) {
+ nSetScrollPosition(mNativeRenderNode, x, y);
}
/**
@@ -890,42 +898,43 @@
// Properties
- private static native void nOffsetTopAndBottom(long renderNode, float offset);
- private static native void nOffsetLeftAndRight(long renderNode, float offset);
- private static native void nSetLeftTopRightBottom(long renderNode, int left, int top,
+ private static native boolean nOffsetTopAndBottom(long renderNode, float offset);
+ private static native boolean nOffsetLeftAndRight(long renderNode, float offset);
+ private static native boolean nSetLeftTopRightBottom(long renderNode, int left, int top,
int right, int bottom);
- private static native void nSetBottom(long renderNode, int bottom);
- private static native void nSetRight(long renderNode, int right);
- private static native void nSetTop(long renderNode, int top);
- private static native void nSetLeft(long renderNode, int left);
- private static native void nSetCameraDistance(long renderNode, float distance);
- private static native void nSetPivotY(long renderNode, float pivotY);
- private static native void nSetPivotX(long renderNode, float pivotX);
- private static native void nSetCaching(long renderNode, boolean caching);
- private static native void nSetClipToBounds(long renderNode, boolean clipToBounds);
- private static native void nSetProjectBackwards(long renderNode, boolean shouldProject);
- private static native void nSetProjectionReceiver(long renderNode, boolean shouldRecieve);
- private static native void nSetOutlineRoundRect(long renderNode, int left, int top,
+ private static native boolean nSetBottom(long renderNode, int bottom);
+ private static native boolean nSetRight(long renderNode, int right);
+ private static native boolean nSetTop(long renderNode, int top);
+ private static native boolean nSetLeft(long renderNode, int left);
+ private static native void nSetScrollPosition(long renderNode, int scrollX, int scrollY);
+ private static native boolean nSetCameraDistance(long renderNode, float distance);
+ private static native boolean nSetPivotY(long renderNode, float pivotY);
+ private static native boolean nSetPivotX(long renderNode, float pivotX);
+ private static native boolean nSetCaching(long renderNode, boolean caching);
+ private static native boolean nSetClipToBounds(long renderNode, boolean clipToBounds);
+ private static native boolean nSetProjectBackwards(long renderNode, boolean shouldProject);
+ private static native boolean nSetProjectionReceiver(long renderNode, boolean shouldRecieve);
+ private static native boolean nSetOutlineRoundRect(long renderNode, int left, int top,
int right, int bottom, float radius);
- private static native void nSetOutlineConvexPath(long renderNode, long nativePath);
- private static native void nSetOutlineEmpty(long renderNode);
- private static native void nSetClipToOutline(long renderNode, boolean clipToOutline);
- private static native void nSetRevealClip(long renderNode,
+ private static native boolean nSetOutlineConvexPath(long renderNode, long nativePath);
+ private static native boolean nSetOutlineEmpty(long renderNode);
+ private static native boolean nSetClipToOutline(long renderNode, boolean clipToOutline);
+ private static native boolean nSetRevealClip(long renderNode,
boolean shouldClip, boolean inverseClip, float x, float y, float radius);
- private static native void nSetAlpha(long renderNode, float alpha);
- private static native void nSetHasOverlappingRendering(long renderNode,
+ private static native boolean nSetAlpha(long renderNode, float alpha);
+ private static native boolean nSetHasOverlappingRendering(long renderNode,
boolean hasOverlappingRendering);
- private static native void nSetElevation(long renderNode, float lift);
- private static native void nSetTranslationX(long renderNode, float translationX);
- private static native void nSetTranslationY(long renderNode, float translationY);
- private static native void nSetTranslationZ(long renderNode, float translationZ);
- private static native void nSetRotation(long renderNode, float rotation);
- private static native void nSetRotationX(long renderNode, float rotationX);
- private static native void nSetRotationY(long renderNode, float rotationY);
- private static native void nSetScaleX(long renderNode, float scaleX);
- private static native void nSetScaleY(long renderNode, float scaleY);
- private static native void nSetStaticMatrix(long renderNode, long nativeMatrix);
- private static native void nSetAnimationMatrix(long renderNode, long animationMatrix);
+ private static native boolean nSetElevation(long renderNode, float lift);
+ private static native boolean nSetTranslationX(long renderNode, float translationX);
+ private static native boolean nSetTranslationY(long renderNode, float translationY);
+ private static native boolean nSetTranslationZ(long renderNode, float translationZ);
+ private static native boolean nSetRotation(long renderNode, float rotation);
+ private static native boolean nSetRotationX(long renderNode, float rotationX);
+ private static native boolean nSetRotationY(long renderNode, float rotationY);
+ private static native boolean nSetScaleX(long renderNode, float scaleX);
+ private static native boolean nSetScaleY(long renderNode, float scaleY);
+ private static native boolean nSetStaticMatrix(long renderNode, long nativeMatrix);
+ private static native boolean nSetAnimationMatrix(long renderNode, long animationMatrix);
private static native boolean nHasOverlappingRendering(long renderNode);
private static native boolean nGetClipToOutline(long renderNode);
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 9b3ef7f..7bbe84e 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -54,8 +54,6 @@
public class ThreadedRenderer extends HardwareRenderer {
private static final String LOGTAG = "ThreadedRenderer";
- private static final Rect NULL_RECT = new Rect();
-
// Keep in sync with DrawFrameTask.h SYNC_* flags
// Nothing interesting to report
private static final int SYNC_OK = 0x0;
@@ -228,7 +226,7 @@
}
@Override
- void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks, Rect dirty) {
+ void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks) {
attachInfo.mIgnoreDirtyState = true;
long frameTimeNanos = mChoreographer.getFrameTimeNanos();
attachInfo.mDrawingTime = frameTimeNanos / TimeUtils.NANOS_PER_MS;
@@ -246,12 +244,8 @@
attachInfo.mIgnoreDirtyState = false;
- if (dirty == null) {
- dirty = NULL_RECT;
- }
int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos,
- recordDuration, view.getResources().getDisplayMetrics().density,
- dirty.left, dirty.top, dirty.right, dirty.bottom);
+ recordDuration, view.getResources().getDisplayMetrics().density);
if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) {
attachInfo.mViewRootImpl.invalidate();
}
@@ -393,8 +387,7 @@
float lightX, float lightY, float lightZ, float lightRadius);
private static native void nSetOpaque(long nativeProxy, boolean opaque);
private static native int nSyncAndDrawFrame(long nativeProxy,
- long frameTimeNanos, long recordDuration, float density,
- int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
+ long frameTimeNanos, long recordDuration, float density);
private static native void nRunWithGlContext(long nativeProxy, Runnable runnable);
private static native void nDestroyCanvasAndSurface(long nativeProxy);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e246c4f..e97a768 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -13732,6 +13732,7 @@
return;
}
+ renderNode.setScrollPosition(mScrollX, mScrollY);
if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0
|| !renderNode.isValid()
|| (!isLayer && mRecreateDisplayList)) {
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 0f40ee7..02011e0 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -4530,6 +4530,28 @@
}
/**
+ * Native-calculated damage path
+ * Returns false if this path was unable to complete successfully. This means
+ * it hit a ViewParent it doesn't recognize and needs to fall back to calculating
+ * damage area
+ * @hide
+ */
+ public boolean damageChildDeferred(View child) {
+ ViewParent parent = getParent();
+ while (parent != null) {
+ if (parent instanceof ViewGroup) {
+ parent = parent.getParent();
+ } else if (parent instanceof ViewRootImpl) {
+ ((ViewRootImpl) parent).invalidate();
+ return true;
+ } else {
+ parent = null;
+ }
+ }
+ return false;
+ }
+
+ /**
* Quick invalidation method called by View.invalidateViewProperty. This doesn't set the
* DRAWN flags and doesn't handle the Animation logic that the default invalidation methods
* do; all we want to do here is schedule a traversal with the appropriate dirty rect.
@@ -4537,6 +4559,10 @@
* @hide
*/
public void damageChild(View child, final Rect dirty) {
+ if (damageChildDeferred(child)) {
+ return;
+ }
+
ViewParent parent = this;
final AttachInfo attachInfo = mAttachInfo;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index f3d1e3c..76d5038 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -181,7 +181,6 @@
int mWidth;
int mHeight;
Rect mDirty;
- final Rect mCurrentDirty = new Rect();
boolean mIsAnimating;
CompatibilityInfo.Translator mTranslator;
@@ -861,7 +860,9 @@
void invalidate() {
mDirty.set(0, 0, mWidth, mHeight);
- scheduleTraversals();
+ if (!mWillDrawSoon) {
+ scheduleTraversals();
+ }
}
void invalidateWorld(View view) {
@@ -2436,12 +2437,10 @@
mHardwareYOffset = yoff;
mResizeAlpha = resizeAlpha;
- mCurrentDirty.set(dirty);
dirty.setEmpty();
mBlockResizeBuffer = false;
- attachInfo.mHardwareRenderer.draw(mView, attachInfo, this,
- animating ? null : mCurrentDirty);
+ attachInfo.mHardwareRenderer.draw(mView, attachInfo, this);
} else {
// If we get here with a disabled & requested hardware renderer, something went
// wrong (an invalidate posted right before we destroyed the hardware surface
diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp
index 879836d..64b077b 100644
--- a/core/jni/android_view_HardwareLayer.cpp
+++ b/core/jni/android_view_HardwareLayer.cpp
@@ -95,13 +95,6 @@
layer->setDisplayList(displayList, left, top, right, bottom);
}
-static jboolean android_view_HardwareLayer_flushChanges(JNIEnv* env, jobject clazz,
- jlong layerUpdaterPtr) {
- DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
- TreeInfo ignoredInfo;
- return layer->apply(ignoredInfo);
-}
-
static jlong android_view_HardwareLayer_getLayer(JNIEnv* env, jobject clazz,
jlong layerUpdaterPtr) {
DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
@@ -135,8 +128,6 @@
{ "nUpdateSurfaceTexture", "(J)V", (void*) android_view_HardwareLayer_updateSurfaceTexture },
{ "nUpdateRenderLayer", "(JJIIII)V", (void*) android_view_HardwareLayer_updateRenderLayer },
- { "nFlushChanges", "(J)Z", (void*) android_view_HardwareLayer_flushChanges },
-
{ "nGetLayer", "(J)J", (void*) android_view_HardwareLayer_getLayer },
{ "nGetTexName", "(J)I", (void*) android_view_HardwareLayer_getTexName },
#endif
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 26022e0..e5f79f2 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -38,6 +38,11 @@
*/
#ifdef USE_OPENGL_RENDERER
+#define SET_AND_DIRTY(prop, val, dirtyFlag) \
+ (reinterpret_cast<RenderNode*>(renderNodePtr)->mutateStagingProperties().prop(val) \
+ ? (reinterpret_cast<RenderNode*>(renderNodePtr)->setPropertyFieldsDirty(dirtyFlag), true) \
+ : false)
+
// ----------------------------------------------------------------------------
// DisplayList view properties
// ----------------------------------------------------------------------------
@@ -82,235 +87,199 @@
// RenderProperties - setters
// ----------------------------------------------------------------------------
-static void android_view_RenderNode_setCaching(JNIEnv* env,
+static jboolean android_view_RenderNode_setCaching(JNIEnv* env,
jobject clazz, jlong renderNodePtr, jboolean caching) {
- RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- renderNode->mutateStagingProperties().setCaching(caching);
- renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
+ return SET_AND_DIRTY(setCaching, caching, RenderNode::GENERIC);
}
-static void android_view_RenderNode_setStaticMatrix(JNIEnv* env,
+static jboolean android_view_RenderNode_setStaticMatrix(JNIEnv* env,
jobject clazz, jlong renderNodePtr, jlong matrixPtr) {
- RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
- renderNode->mutateStagingProperties().setStaticMatrix(matrix);
- renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
+ return SET_AND_DIRTY(setStaticMatrix, matrix, RenderNode::GENERIC);
}
-static void android_view_RenderNode_setAnimationMatrix(JNIEnv* env,
+static jboolean android_view_RenderNode_setAnimationMatrix(JNIEnv* env,
jobject clazz, jlong renderNodePtr, jlong matrixPtr) {
- RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
- renderNode->mutateStagingProperties().setAnimationMatrix(matrix);
- renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
+ return SET_AND_DIRTY(setAnimationMatrix, matrix, RenderNode::GENERIC);
}
-static void android_view_RenderNode_setClipToBounds(JNIEnv* env,
+static jboolean android_view_RenderNode_setClipToBounds(JNIEnv* env,
jobject clazz, jlong renderNodePtr, jboolean clipToBounds) {
- RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- renderNode->mutateStagingProperties().setClipToBounds(clipToBounds);
- renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
+ return SET_AND_DIRTY(setClipToBounds, clipToBounds, RenderNode::GENERIC);
}
-static void android_view_RenderNode_setProjectBackwards(JNIEnv* env,
+static jboolean android_view_RenderNode_setProjectBackwards(JNIEnv* env,
jobject clazz, jlong renderNodePtr, jboolean shouldProject) {
- RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- renderNode->mutateStagingProperties().setProjectBackwards(shouldProject);
- renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
+ return SET_AND_DIRTY(setProjectBackwards, shouldProject, RenderNode::GENERIC);
}
-static void android_view_RenderNode_setProjectionReceiver(JNIEnv* env,
+static jboolean android_view_RenderNode_setProjectionReceiver(JNIEnv* env,
jobject clazz, jlong renderNodePtr, jboolean shouldRecieve) {
- RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- renderNode->mutateStagingProperties().setProjectionReceiver(shouldRecieve);
- renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
+ return SET_AND_DIRTY(setProjectionReceiver, shouldRecieve, RenderNode::GENERIC);
}
-static void android_view_RenderNode_setOutlineRoundRect(JNIEnv* env,
+static jboolean android_view_RenderNode_setOutlineRoundRect(JNIEnv* env,
jobject clazz, jlong renderNodePtr, jint left, jint top,
jint right, jint bottom, jfloat radius) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().mutableOutline().setRoundRect(left, top, right, bottom, radius);
renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
+ return true;
}
-static void android_view_RenderNode_setOutlineConvexPath(JNIEnv* env,
+static jboolean android_view_RenderNode_setOutlineConvexPath(JNIEnv* env,
jobject clazz, jlong renderNodePtr, jlong outlinePathPtr) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
SkPath* outlinePath = reinterpret_cast<SkPath*>(outlinePathPtr);
renderNode->mutateStagingProperties().mutableOutline().setConvexPath(outlinePath);
renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
+ return true;
}
-static void android_view_RenderNode_setOutlineEmpty(JNIEnv* env,
+static jboolean android_view_RenderNode_setOutlineEmpty(JNIEnv* env,
jobject clazz, jlong renderNodePtr) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().mutableOutline().setEmpty();
renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
+ return true;
}
-static void android_view_RenderNode_setClipToOutline(JNIEnv* env,
+static jboolean android_view_RenderNode_setClipToOutline(JNIEnv* env,
jobject clazz, jlong renderNodePtr, jboolean clipToOutline) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().mutableOutline().setShouldClip(clipToOutline);
renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
+ return true;
}
-static void android_view_RenderNode_setRevealClip(JNIEnv* env,
+static jboolean android_view_RenderNode_setRevealClip(JNIEnv* env,
jobject clazz, jlong renderNodePtr, jboolean shouldClip, jboolean inverseClip,
jfloat x, jfloat y, jfloat radius) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
renderNode->mutateStagingProperties().mutableRevealClip().set(
shouldClip, inverseClip, x, y, radius);
renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
+ return true;
}
-static void android_view_RenderNode_setAlpha(JNIEnv* env,
+static jboolean android_view_RenderNode_setAlpha(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float alpha) {
- RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- renderNode->mutateStagingProperties().setAlpha(alpha);
- renderNode->setPropertyFieldsDirty(RenderNode::ALPHA);
+ return SET_AND_DIRTY(setAlpha, alpha, RenderNode::ALPHA);
}
-static void android_view_RenderNode_setHasOverlappingRendering(JNIEnv* env,
+static jboolean android_view_RenderNode_setHasOverlappingRendering(JNIEnv* env,
jobject clazz, jlong renderNodePtr, bool hasOverlappingRendering) {
- RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- renderNode->mutateStagingProperties().setHasOverlappingRendering(hasOverlappingRendering);
- renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
+ return SET_AND_DIRTY(setHasOverlappingRendering, hasOverlappingRendering,
+ RenderNode::GENERIC);
}
-static void android_view_RenderNode_setElevation(JNIEnv* env,
+static jboolean android_view_RenderNode_setElevation(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float elevation) {
- RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- renderNode->mutateStagingProperties().setElevation(elevation);
- renderNode->setPropertyFieldsDirty(RenderNode::Z);
+ return SET_AND_DIRTY(setElevation, elevation, RenderNode::Z);
}
-static void android_view_RenderNode_setTranslationX(JNIEnv* env,
+static jboolean android_view_RenderNode_setTranslationX(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float tx) {
- RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- renderNode->mutateStagingProperties().setTranslationX(tx);
- renderNode->setPropertyFieldsDirty(RenderNode::TRANSLATION_X | RenderNode::X);
+ return SET_AND_DIRTY(setTranslationX, tx, RenderNode::TRANSLATION_X | RenderNode::X);
}
-static void android_view_RenderNode_setTranslationY(JNIEnv* env,
+static jboolean android_view_RenderNode_setTranslationY(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float ty) {
- RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- renderNode->mutateStagingProperties().setTranslationY(ty);
- renderNode->setPropertyFieldsDirty(RenderNode::TRANSLATION_Y | RenderNode::Y);
+ return SET_AND_DIRTY(setTranslationY, ty, RenderNode::TRANSLATION_Y | RenderNode::Y);
}
-static void android_view_RenderNode_setTranslationZ(JNIEnv* env,
+static jboolean android_view_RenderNode_setTranslationZ(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float tz) {
- RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- renderNode->mutateStagingProperties().setTranslationZ(tz);
- renderNode->setPropertyFieldsDirty(RenderNode::TRANSLATION_Z | RenderNode::Z);
+ return SET_AND_DIRTY(setTranslationZ, tz, RenderNode::TRANSLATION_Z | RenderNode::Z);
}
-static void android_view_RenderNode_setRotation(JNIEnv* env,
+static jboolean android_view_RenderNode_setRotation(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float rotation) {
- RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- renderNode->mutateStagingProperties().setRotation(rotation);
- renderNode->setPropertyFieldsDirty(RenderNode::ROTATION);
+ return SET_AND_DIRTY(setRotation, rotation, RenderNode::ROTATION);
}
-static void android_view_RenderNode_setRotationX(JNIEnv* env,
+static jboolean android_view_RenderNode_setRotationX(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float rx) {
- RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- renderNode->mutateStagingProperties().setRotationX(rx);
- renderNode->setPropertyFieldsDirty(RenderNode::ROTATION_X);
+ return SET_AND_DIRTY(setRotationX, rx, RenderNode::ROTATION_X);
}
-static void android_view_RenderNode_setRotationY(JNIEnv* env,
+static jboolean android_view_RenderNode_setRotationY(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float ry) {
- RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- renderNode->mutateStagingProperties().setRotationY(ry);
- renderNode->setPropertyFieldsDirty(RenderNode::ROTATION_Y);
+ return SET_AND_DIRTY(setRotationY, ry, RenderNode::ROTATION_Y);
}
-static void android_view_RenderNode_setScaleX(JNIEnv* env,
+static jboolean android_view_RenderNode_setScaleX(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float sx) {
- RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- renderNode->mutateStagingProperties().setScaleX(sx);
- renderNode->setPropertyFieldsDirty(RenderNode::SCALE_X);
+ return SET_AND_DIRTY(setScaleX, sx, RenderNode::SCALE_X);
}
-static void android_view_RenderNode_setScaleY(JNIEnv* env,
+static jboolean android_view_RenderNode_setScaleY(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float sy) {
- RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- renderNode->mutateStagingProperties().setScaleY(sy);
- renderNode->setPropertyFieldsDirty(RenderNode::SCALE_Y);
+ return SET_AND_DIRTY(setScaleY, sy, RenderNode::SCALE_Y);
}
-static void android_view_RenderNode_setPivotX(JNIEnv* env,
+static jboolean android_view_RenderNode_setPivotX(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float px) {
- RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- renderNode->mutateStagingProperties().setPivotX(px);
- renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
+ return SET_AND_DIRTY(setPivotX, px, RenderNode::GENERIC);
}
-static void android_view_RenderNode_setPivotY(JNIEnv* env,
+static jboolean android_view_RenderNode_setPivotY(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float py) {
- RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- renderNode->mutateStagingProperties().setPivotY(py);
- renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
+ return SET_AND_DIRTY(setPivotY, py, RenderNode::GENERIC);
}
-static void android_view_RenderNode_setCameraDistance(JNIEnv* env,
+static jboolean android_view_RenderNode_setCameraDistance(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float distance) {
- RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- renderNode->mutateStagingProperties().setCameraDistance(distance);
- renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
+ return SET_AND_DIRTY(setCameraDistance, distance, RenderNode::GENERIC);
}
-static void android_view_RenderNode_setLeft(JNIEnv* env,
+static jboolean android_view_RenderNode_setLeft(JNIEnv* env,
jobject clazz, jlong renderNodePtr, int left) {
- RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- renderNode->mutateStagingProperties().setLeft(left);
- renderNode->setPropertyFieldsDirty(RenderNode::X);
+ return SET_AND_DIRTY(setLeft, left, RenderNode::X);
}
-static void android_view_RenderNode_setTop(JNIEnv* env,
+static jboolean android_view_RenderNode_setTop(JNIEnv* env,
jobject clazz, jlong renderNodePtr, int top) {
- RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- renderNode->mutateStagingProperties().setTop(top);
- renderNode->setPropertyFieldsDirty(RenderNode::Y);
+ return SET_AND_DIRTY(setTop, top, RenderNode::Y);
}
-static void android_view_RenderNode_setRight(JNIEnv* env,
+static jboolean android_view_RenderNode_setRight(JNIEnv* env,
jobject clazz, jlong renderNodePtr, int right) {
- RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- renderNode->mutateStagingProperties().setRight(right);
- renderNode->setPropertyFieldsDirty(RenderNode::X);
+ return SET_AND_DIRTY(setRight, right, RenderNode::X);
}
-static void android_view_RenderNode_setBottom(JNIEnv* env,
+static jboolean android_view_RenderNode_setBottom(JNIEnv* env,
jobject clazz, jlong renderNodePtr, int bottom) {
- RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- renderNode->mutateStagingProperties().setBottom(bottom);
- renderNode->setPropertyFieldsDirty(RenderNode::Y);
+ return SET_AND_DIRTY(setBottom, bottom, RenderNode::Y);
}
-static void android_view_RenderNode_setLeftTopRightBottom(JNIEnv* env,
+static jboolean android_view_RenderNode_setLeftTopRightBottom(JNIEnv* env,
jobject clazz, jlong renderNodePtr, int left, int top,
int right, int bottom) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- renderNode->mutateStagingProperties().setLeftTopRightBottom(left, top, right, bottom);
- renderNode->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+ if (renderNode->mutateStagingProperties().setLeftTopRightBottom(left, top, right, bottom)) {
+ renderNode->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+ return true;
+ }
+ return false;
}
-static void android_view_RenderNode_offsetLeftAndRight(JNIEnv* env,
+static jboolean android_view_RenderNode_offsetLeftAndRight(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float offset) {
- RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- renderNode->mutateStagingProperties().offsetLeftRight(offset);
- renderNode->setPropertyFieldsDirty(RenderNode::X);
+ return SET_AND_DIRTY(offsetLeftRight, offset, RenderNode::X);
}
-static void android_view_RenderNode_offsetTopAndBottom(JNIEnv* env,
+static jboolean android_view_RenderNode_offsetTopAndBottom(JNIEnv* env,
jobject clazz, jlong renderNodePtr, float offset) {
+ return SET_AND_DIRTY(offsetTopBottom, offset, RenderNode::Y);
+}
+
+static void android_view_RenderNode_setScrollPosition(JNIEnv* env,
+ jobject clazz, jlong renderNodePtr, jint scrollX, jint scrollY) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
- renderNode->mutateStagingProperties().offsetTopBottom(offset);
- renderNode->setPropertyFieldsDirty(RenderNode::Y);
+ SET_AND_DIRTY(setScrollX, scrollX, RenderNode::GENERIC);
+ SET_AND_DIRTY(setScrollY, scrollY, RenderNode::GENERIC);
}
// ----------------------------------------------------------------------------
@@ -513,41 +482,42 @@
{ "nOutput", "(J)V", (void*) android_view_RenderNode_output },
{ "nGetDebugSize", "(J)I", (void*) android_view_RenderNode_getDebugSize },
- { "nSetCaching", "(JZ)V", (void*) android_view_RenderNode_setCaching },
- { "nSetStaticMatrix", "(JJ)V", (void*) android_view_RenderNode_setStaticMatrix },
- { "nSetAnimationMatrix", "(JJ)V", (void*) android_view_RenderNode_setAnimationMatrix },
- { "nSetClipToBounds", "(JZ)V", (void*) android_view_RenderNode_setClipToBounds },
- { "nSetProjectBackwards", "(JZ)V", (void*) android_view_RenderNode_setProjectBackwards },
- { "nSetProjectionReceiver","(JZ)V", (void*) android_view_RenderNode_setProjectionReceiver },
+ { "nSetCaching", "(JZ)Z", (void*) android_view_RenderNode_setCaching },
+ { "nSetStaticMatrix", "(JJ)Z", (void*) android_view_RenderNode_setStaticMatrix },
+ { "nSetAnimationMatrix", "(JJ)Z", (void*) android_view_RenderNode_setAnimationMatrix },
+ { "nSetClipToBounds", "(JZ)Z", (void*) android_view_RenderNode_setClipToBounds },
+ { "nSetProjectBackwards", "(JZ)Z", (void*) android_view_RenderNode_setProjectBackwards },
+ { "nSetProjectionReceiver","(JZ)Z", (void*) android_view_RenderNode_setProjectionReceiver },
- { "nSetOutlineRoundRect", "(JIIIIF)V", (void*) android_view_RenderNode_setOutlineRoundRect },
- { "nSetOutlineConvexPath", "(JJ)V", (void*) android_view_RenderNode_setOutlineConvexPath },
- { "nSetOutlineEmpty", "(J)V", (void*) android_view_RenderNode_setOutlineEmpty },
- { "nSetClipToOutline", "(JZ)V", (void*) android_view_RenderNode_setClipToOutline },
- { "nSetRevealClip", "(JZZFFF)V", (void*) android_view_RenderNode_setRevealClip },
+ { "nSetOutlineRoundRect", "(JIIIIF)Z", (void*) android_view_RenderNode_setOutlineRoundRect },
+ { "nSetOutlineConvexPath", "(JJ)Z", (void*) android_view_RenderNode_setOutlineConvexPath },
+ { "nSetOutlineEmpty", "(J)Z", (void*) android_view_RenderNode_setOutlineEmpty },
+ { "nSetClipToOutline", "(JZ)Z", (void*) android_view_RenderNode_setClipToOutline },
+ { "nSetRevealClip", "(JZZFFF)Z", (void*) android_view_RenderNode_setRevealClip },
- { "nSetAlpha", "(JF)V", (void*) android_view_RenderNode_setAlpha },
- { "nSetHasOverlappingRendering", "(JZ)V",
+ { "nSetAlpha", "(JF)Z", (void*) android_view_RenderNode_setAlpha },
+ { "nSetHasOverlappingRendering", "(JZ)Z",
(void*) android_view_RenderNode_setHasOverlappingRendering },
- { "nSetElevation", "(JF)V", (void*) android_view_RenderNode_setElevation },
- { "nSetTranslationX", "(JF)V", (void*) android_view_RenderNode_setTranslationX },
- { "nSetTranslationY", "(JF)V", (void*) android_view_RenderNode_setTranslationY },
- { "nSetTranslationZ", "(JF)V", (void*) android_view_RenderNode_setTranslationZ },
- { "nSetRotation", "(JF)V", (void*) android_view_RenderNode_setRotation },
- { "nSetRotationX", "(JF)V", (void*) android_view_RenderNode_setRotationX },
- { "nSetRotationY", "(JF)V", (void*) android_view_RenderNode_setRotationY },
- { "nSetScaleX", "(JF)V", (void*) android_view_RenderNode_setScaleX },
- { "nSetScaleY", "(JF)V", (void*) android_view_RenderNode_setScaleY },
- { "nSetPivotX", "(JF)V", (void*) android_view_RenderNode_setPivotX },
- { "nSetPivotY", "(JF)V", (void*) android_view_RenderNode_setPivotY },
- { "nSetCameraDistance", "(JF)V", (void*) android_view_RenderNode_setCameraDistance },
- { "nSetLeft", "(JI)V", (void*) android_view_RenderNode_setLeft },
- { "nSetTop", "(JI)V", (void*) android_view_RenderNode_setTop },
- { "nSetRight", "(JI)V", (void*) android_view_RenderNode_setRight },
- { "nSetBottom", "(JI)V", (void*) android_view_RenderNode_setBottom },
- { "nSetLeftTopRightBottom","(JIIII)V", (void*) android_view_RenderNode_setLeftTopRightBottom },
- { "nOffsetLeftAndRight", "(JF)V", (void*) android_view_RenderNode_offsetLeftAndRight },
- { "nOffsetTopAndBottom", "(JF)V", (void*) android_view_RenderNode_offsetTopAndBottom },
+ { "nSetElevation", "(JF)Z", (void*) android_view_RenderNode_setElevation },
+ { "nSetTranslationX", "(JF)Z", (void*) android_view_RenderNode_setTranslationX },
+ { "nSetTranslationY", "(JF)Z", (void*) android_view_RenderNode_setTranslationY },
+ { "nSetTranslationZ", "(JF)Z", (void*) android_view_RenderNode_setTranslationZ },
+ { "nSetRotation", "(JF)Z", (void*) android_view_RenderNode_setRotation },
+ { "nSetRotationX", "(JF)Z", (void*) android_view_RenderNode_setRotationX },
+ { "nSetRotationY", "(JF)Z", (void*) android_view_RenderNode_setRotationY },
+ { "nSetScaleX", "(JF)Z", (void*) android_view_RenderNode_setScaleX },
+ { "nSetScaleY", "(JF)Z", (void*) android_view_RenderNode_setScaleY },
+ { "nSetPivotX", "(JF)Z", (void*) android_view_RenderNode_setPivotX },
+ { "nSetPivotY", "(JF)Z", (void*) android_view_RenderNode_setPivotY },
+ { "nSetCameraDistance", "(JF)Z", (void*) android_view_RenderNode_setCameraDistance },
+ { "nSetLeft", "(JI)Z", (void*) android_view_RenderNode_setLeft },
+ { "nSetTop", "(JI)Z", (void*) android_view_RenderNode_setTop },
+ { "nSetRight", "(JI)Z", (void*) android_view_RenderNode_setRight },
+ { "nSetBottom", "(JI)Z", (void*) android_view_RenderNode_setBottom },
+ { "nSetLeftTopRightBottom","(JIIII)Z", (void*) android_view_RenderNode_setLeftTopRightBottom },
+ { "nOffsetLeftAndRight", "(JF)Z", (void*) android_view_RenderNode_offsetLeftAndRight },
+ { "nOffsetTopAndBottom", "(JF)Z", (void*) android_view_RenderNode_offsetTopAndBottom },
+ { "nSetScrollPosition", "(JII)V", (void*) android_view_RenderNode_setScrollPosition },
{ "nHasOverlappingRendering", "(J)Z", (void*) android_view_RenderNode_hasOverlappingRendering },
{ "nGetClipToOutline", "(J)Z", (void*) android_view_RenderNode_getClipToOutline },
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index a550649..815c4a7 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -150,6 +150,13 @@
}
}
+protected:
+ virtual void damageSelf(TreeInfo& info) {
+ // Intentionally a no-op. As RootRenderNode gets a new DisplayListData
+ // every frame this would result in every draw push being a full inval,
+ // which is wrong. Only RootRenderNode has this issue.
+ }
+
private:
sp<Looper> mLooper;
std::vector<OnFinishedEvent> mOnFinishedEvents;
@@ -242,11 +249,9 @@
}
static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
- jlong proxyPtr, jlong frameTimeNanos, jlong recordDuration, jfloat density,
- jint dirtyLeft, jint dirtyTop, jint dirtyRight, jint dirtyBottom) {
+ jlong proxyPtr, jlong frameTimeNanos, jlong recordDuration, jfloat density) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
- return proxy->syncAndDrawFrame(frameTimeNanos, recordDuration, density,
- dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
+ return proxy->syncAndDrawFrame(frameTimeNanos, recordDuration, density);
}
static void android_view_ThreadedRenderer_destroyCanvasAndSurface(JNIEnv* env, jobject clazz,
@@ -363,7 +368,7 @@
{ "nPauseSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_pauseSurface },
{ "nSetup", "(JIIFFFF)V", (void*) android_view_ThreadedRenderer_setup },
{ "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
- { "nSyncAndDrawFrame", "(JJJFIIII)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
+ { "nSyncAndDrawFrame", "(JJJF)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
{ "nDestroyCanvasAndSurface", "(J)V", (void*) android_view_ThreadedRenderer_destroyCanvasAndSurface },
{ "nInvokeFunctor", "(JJZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
{ "nRunWithGlContext", "(JLjava/lang/Runnable;)V", (void*) android_view_ThreadedRenderer_runWithGlContext },
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index e5c8898..cc62170 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -14,6 +14,7 @@
AmbientShadow.cpp \
Animator.cpp \
AssetAtlas.cpp \
+ DamageAccumulator.cpp \
FontRenderer.cpp \
GammaFontRenderer.cpp \
Caches.cpp \
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index a0c7c55..203cdff 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -117,7 +117,7 @@
virtual void setValue(RenderNode* target, float value);
private:
- typedef void (RenderProperties::*SetFloatProperty)(float value);
+ typedef bool (RenderProperties::*SetFloatProperty)(float value);
typedef float (RenderProperties::*GetFloatProperty)() const;
struct PropertyAccessors;
diff --git a/libs/hwui/DamageAccumulator.cpp b/libs/hwui/DamageAccumulator.cpp
new file mode 100644
index 0000000..8aa8c92
--- /dev/null
+++ b/libs/hwui/DamageAccumulator.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "DamageAccumulator"
+
+#include "DamageAccumulator.h"
+
+#include <cutils/log.h>
+
+#include "RenderNode.h"
+#include "utils/MathUtils.h"
+
+namespace android {
+namespace uirenderer {
+
+struct DirtyStack {
+ const RenderNode* node;
+ // When this frame is pop'd, this rect is mapped through the above transform
+ // and applied to the previous (aka parent) frame
+ SkRect pendingDirty;
+ DirtyStack* prev;
+ DirtyStack* next;
+};
+
+DamageAccumulator::DamageAccumulator() {
+ mHead = (DirtyStack*) mAllocator.alloc(sizeof(DirtyStack));
+ memset(mHead, 0, sizeof(DirtyStack));
+ // Create a root that we will not pop off
+ mHead->prev = mHead;
+}
+
+void DamageAccumulator::pushNode(const RenderNode* node) {
+ if (!mHead->next) {
+ DirtyStack* nextFrame = (DirtyStack*) mAllocator.alloc(sizeof(DirtyStack));
+ nextFrame->next = 0;
+ nextFrame->prev = mHead;
+ mHead->next = nextFrame;
+ }
+ mHead = mHead->next;
+ mHead->node = node;
+ mHead->pendingDirty.setEmpty();
+}
+
+void DamageAccumulator::popNode() {
+ LOG_ALWAYS_FATAL_IF(mHead->prev == mHead, "Cannot pop the root frame!");
+ DirtyStack* dirtyFrame = mHead;
+ mHead = mHead->prev;
+ if (!dirtyFrame->pendingDirty.isEmpty()) {
+ SkRect mappedDirty;
+ const RenderProperties& props = dirtyFrame->node->properties();
+ const SkMatrix* transform = props.getTransformMatrix();
+ if (transform && !transform->isIdentity()) {
+ transform->mapRect(&mappedDirty, dirtyFrame->pendingDirty);
+ } else {
+ mappedDirty = dirtyFrame->pendingDirty;
+ }
+ if (CC_LIKELY(mHead->node)) {
+ const RenderProperties& parentProps = mHead->node->properties();
+ mappedDirty.offset(props.getLeft() - parentProps.getScrollX(),
+ props.getTop() - parentProps.getScrollY());
+ if (props.getClipToBounds()) {
+ if (!mappedDirty.intersect(0, 0, parentProps.getWidth(), parentProps.getHeight())) {
+ mappedDirty.setEmpty();
+ }
+ }
+ if (CC_UNLIKELY(!MathUtils::isZero(props.getTranslationZ()))) {
+ // TODO: Can we better bound the shadow damage area? For now
+ // match the old damageShadowReceiver() path and just dirty
+ // the entire parent bounds
+ mappedDirty.join(0, 0, parentProps.getWidth(), parentProps.getHeight());
+ }
+ } else {
+ mappedDirty.offset(props.getLeft(), props.getTop());
+ }
+ dirty(mappedDirty.fLeft, mappedDirty.fTop, mappedDirty.fRight, mappedDirty.fBottom);
+ }
+}
+
+void DamageAccumulator::dirty(float left, float top, float right, float bottom) {
+ mHead->pendingDirty.join(left, top, right, bottom);
+}
+
+void DamageAccumulator::finish(SkRect* totalDirty) {
+ LOG_ALWAYS_FATAL_IF(mHead->prev != mHead, "Cannot finish, mismatched push/pop calls! %p vs. %p", mHead->prev, mHead);
+ // Root node never has a transform, so this is the fully mapped dirty rect
+ *totalDirty = mHead->pendingDirty;
+ totalDirty->roundOut();
+ mHead->pendingDirty.setEmpty();
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/DamageAccumulator.h b/libs/hwui/DamageAccumulator.h
new file mode 100644
index 0000000..c62a351
--- /dev/null
+++ b/libs/hwui/DamageAccumulator.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef DAMAGEACCUMULATOR_H
+#define DAMAGEACCUMULATOR_H
+
+#include <utils/LinearAllocator.h>
+
+#include <SkMatrix.h>
+#include <SkRect.h>
+
+#include "utils/Macros.h"
+
+namespace android {
+namespace uirenderer {
+
+struct DirtyStack;
+class RenderNode;
+
+class DamageAccumulator {
+ PREVENT_COPY_AND_ASSIGN(DamageAccumulator);
+public:
+ DamageAccumulator();
+ // mAllocator will clean everything up for us, no need for a dtor
+
+ // Push a transform node onto the stack. This should be called prior
+ // to any dirty() calls. Subsequent calls to dirty()
+ // will be affected by the node's transform when popNode() is called.
+ void pushNode(const RenderNode* node);
+ // Pops a transform node from the stack, propagating the dirty rect
+ // up to the parent node.
+ void popNode();
+ void dirty(float left, float top, float right, float bottom);
+
+ void finish(SkRect* totalDirty);
+
+private:
+ LinearAllocator mAllocator;
+ DirtyStack* mHead;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* DAMAGEACCUMULATOR_H */
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 97e9bf6..d494c4c 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -81,6 +81,10 @@
success = LayerRenderer::resizeLayer(mLayer, mWidth, mHeight);
}
mLayer->setBlend(mBlend);
+ // TODO: Use DamageAccumulator to get the damage area for the layer's
+ // subtree to only update that part of the layer. Do this as part of
+ // reworking layers to be a RenderProperty instead of a View-managed object
+ mDirtyRect.set(0, 0, mWidth, mHeight);
mDisplayList->prepareTree(info);
mLayer->updateDeferred(mDisplayList.get(),
mDirtyRect.left, mDirtyRect.top, mDirtyRect.right, mDirtyRect.bottom);
diff --git a/libs/hwui/DrawProfiler.cpp b/libs/hwui/DrawProfiler.cpp
index 971a66e..2409554 100644
--- a/libs/hwui/DrawProfiler.cpp
+++ b/libs/hwui/DrawProfiler.cpp
@@ -109,7 +109,7 @@
mCurrentFrame = (mCurrentFrame + 1) % mDataSize;
}
-void DrawProfiler::unionDirty(Rect* dirty) {
+void DrawProfiler::unionDirty(SkRect* dirty) {
RETURN_IF_DISABLED();
// Not worth worrying about minimizing the dirty region for debugging, so just
// dirty the entire viewport.
diff --git a/libs/hwui/DrawProfiler.h b/libs/hwui/DrawProfiler.h
index c1aa1c6..7c06e5d 100644
--- a/libs/hwui/DrawProfiler.h
+++ b/libs/hwui/DrawProfiler.h
@@ -37,7 +37,7 @@
void markPlaybackEnd();
void finishFrame();
- void unionDirty(Rect* dirty);
+ void unionDirty(SkRect* dirty);
void draw(OpenGLRenderer* canvas);
void dumpData(int fd);
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index baf372a..c2f6df8 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -25,6 +25,7 @@
#include <utils/Trace.h>
+#include "DamageAccumulator.h"
#include "Debug.h"
#include "DisplayListOp.h"
#include "DisplayListLogBuffer.h"
@@ -110,14 +111,36 @@
prepareTreeImpl(info);
}
-void RenderNode::prepareTreeImpl(TreeInfo& info) {
- if (info.performStagingPush) {
- pushStagingChanges(info);
+static inline void pushNode(RenderNode* self, TreeInfo& info) {
+ if (info.damageAccumulator) {
+ info.damageAccumulator->pushNode(self);
}
- if (info.evaluateAnimations) {
+}
+
+static inline void popNode(TreeInfo& info) {
+ if (info.damageAccumulator) {
+ info.damageAccumulator->popNode();
+ }
+}
+
+void RenderNode::damageSelf(TreeInfo& info) {
+ if (info.damageAccumulator && isRenderable() && properties().getAlpha() > 0) {
+ info.damageAccumulator->dirty(0, 0, properties().getWidth(), properties().getHeight());
+ }
+}
+
+void RenderNode::prepareTreeImpl(TreeInfo& info) {
+ pushNode(this, info);
+ if (info.mode == TreeInfo::MODE_FULL) {
+ pushStagingChanges(info);
+ evaluateAnimations(info);
+ } else if (info.mode == TreeInfo::MODE_MAYBE_DETACHING) {
+ pushStagingChanges(info);
+ } else if (info.mode == TreeInfo::MODE_RT_ONLY) {
evaluateAnimations(info);
}
prepareSubTree(info, mDisplayListData);
+ popNode(info);
}
class PushAnimatorsFunctor {
@@ -149,18 +172,28 @@
}
if (mDirtyPropertyFields) {
mDirtyPropertyFields = 0;
+ damageSelf(info);
+ popNode(info);
mProperties = mStagingProperties;
+ pushNode(this, info);
+ // We could try to be clever and only re-damage if the matrix changed.
+ // However, we don't need to worry about that. The cost of over-damaging
+ // here is only going to be a single additional map rect of this node
+ // plus a rect join(). The parent's transform (and up) will only be
+ // performed once.
+ damageSelf(info);
}
if (mNeedsDisplayListDataSync) {
mNeedsDisplayListDataSync = false;
// Do a push pass on the old tree to handle freeing DisplayListData
// that are no longer used
- TreeInfo oldTreeInfo;
+ TreeInfo oldTreeInfo(TreeInfo::MODE_MAYBE_DETACHING);
+ oldTreeInfo.damageAccumulator = info.damageAccumulator;
prepareSubTree(oldTreeInfo, mDisplayListData);
- // TODO: The damage for the old tree should be accounted for
delete mDisplayListData;
mDisplayListData = mStagingDisplayListData;
mStagingDisplayListData = 0;
+ damageSelf(info);
}
}
@@ -180,12 +213,21 @@
void RenderNode::evaluateAnimations(TreeInfo& info) {
if (!mAnimators.size()) return;
+ // TODO: Can we target this better? For now treat it like any other staging
+ // property push and just damage self before and after animators are run
+
+ damageSelf(info);
+ popNode(info);
+
AnimateFunctor functor(this, info);
std::vector< sp<BaseRenderNodeAnimator> >::iterator newEnd;
newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
mAnimators.erase(newEnd, mAnimators.end());
mProperties.updateMatrix();
info.out.hasAnimations |= mAnimators.size();
+
+ pushNode(this, info);
+ damageSelf(info);
}
void RenderNode::prepareSubTree(TreeInfo& info, DisplayListData* subtree) {
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 1a5377b..393d4ea 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -148,7 +148,7 @@
mDirtyPropertyFields |= fields;
}
- const RenderProperties& properties() {
+ const RenderProperties& properties() const {
return mProperties;
}
@@ -187,6 +187,9 @@
mNeedsAnimatorsSync = true;
}
+protected:
+ virtual void damageSelf(TreeInfo& info);
+
private:
typedef key_value_pair_t<float, DrawDisplayListOp*> ZDrawDisplayListOpPair;
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index 5f7d4e3..6163df5 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -44,6 +44,7 @@
, mPivotX(0), mPivotY(0)
, mLeft(0), mTop(0), mRight(0), mBottom(0)
, mWidth(0), mHeight(0)
+ , mScrollX(0), mScrollY(0)
, mPivotExplicitlySet(false)
, mMatrixOrPivotDirty(false)
, mCaching(false) {
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index c0e3ce7..c294f38 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -40,6 +40,10 @@
class Matrix4;
class RenderNode;
+// The __VA_ARGS__ will be executed if a & b are not equal
+#define RP_SET(a, b, ...) (a != b ? (a = b, ##__VA_ARGS__, true) : false)
+#define RP_SET_AND_DIRTY(a, b) RP_SET(a, b, mPrimitiveFields.mMatrixOrPivotDirty = true)
+
/*
* Data structure that holds the properties for a RenderNode
*/
@@ -50,29 +54,30 @@
RenderProperties& operator=(const RenderProperties& other);
- void setClipToBounds(bool clipToBounds) {
- mPrimitiveFields.mClipToBounds = clipToBounds;
+ bool setClipToBounds(bool clipToBounds) {
+ return RP_SET(mPrimitiveFields.mClipToBounds, clipToBounds);
}
- void setProjectBackwards(bool shouldProject) {
- mPrimitiveFields.mProjectBackwards = shouldProject;
+ bool setProjectBackwards(bool shouldProject) {
+ return RP_SET(mPrimitiveFields.mProjectBackwards, shouldProject);
}
- void setProjectionReceiver(bool shouldRecieve) {
- mPrimitiveFields.mProjectionReceiver = shouldRecieve;
+ bool setProjectionReceiver(bool shouldRecieve) {
+ return RP_SET(mPrimitiveFields.mProjectionReceiver, shouldRecieve);
}
bool isProjectionReceiver() const {
return mPrimitiveFields.mProjectionReceiver;
}
- void setStaticMatrix(const SkMatrix* matrix) {
+ bool setStaticMatrix(const SkMatrix* matrix) {
delete mStaticMatrix;
if (matrix) {
mStaticMatrix = new SkMatrix(*matrix);
} else {
mStaticMatrix = NULL;
}
+ return true;
}
// Can return NULL
@@ -80,72 +85,61 @@
return mStaticMatrix;
}
- void setAnimationMatrix(const SkMatrix* matrix) {
+ bool setAnimationMatrix(const SkMatrix* matrix) {
delete mAnimationMatrix;
if (matrix) {
mAnimationMatrix = new SkMatrix(*matrix);
} else {
mAnimationMatrix = NULL;
}
+ return true;
}
- void setAlpha(float alpha) {
+ bool setAlpha(float alpha) {
alpha = fminf(1.0f, fmaxf(0.0f, alpha));
- if (alpha != mPrimitiveFields.mAlpha) {
- mPrimitiveFields.mAlpha = alpha;
- }
+ return RP_SET(mPrimitiveFields.mAlpha, alpha);
}
float getAlpha() const {
return mPrimitiveFields.mAlpha;
}
- void setHasOverlappingRendering(bool hasOverlappingRendering) {
- mPrimitiveFields.mHasOverlappingRendering = hasOverlappingRendering;
+ bool setHasOverlappingRendering(bool hasOverlappingRendering) {
+ return RP_SET(mPrimitiveFields.mHasOverlappingRendering, hasOverlappingRendering);
}
bool hasOverlappingRendering() const {
return mPrimitiveFields.mHasOverlappingRendering;
}
- void setElevation(float elevation) {
- if (elevation != mPrimitiveFields.mElevation) {
- mPrimitiveFields.mElevation = elevation;
- // mMatrixOrPivotDirty not set, since matrix doesn't respect Z
- }
+ bool setElevation(float elevation) {
+ return RP_SET(mPrimitiveFields.mElevation, elevation);
+ // Don't dirty matrix/pivot, since they don't respect Z
}
float getElevation() const {
return mPrimitiveFields.mElevation;
}
- void setTranslationX(float translationX) {
- if (translationX != mPrimitiveFields.mTranslationX) {
- mPrimitiveFields.mTranslationX = translationX;
- mPrimitiveFields.mMatrixOrPivotDirty = true;
- }
+ bool setTranslationX(float translationX) {
+ return RP_SET_AND_DIRTY(mPrimitiveFields.mTranslationX, translationX);
}
float getTranslationX() const {
return mPrimitiveFields.mTranslationX;
}
- void setTranslationY(float translationY) {
- if (translationY != mPrimitiveFields.mTranslationY) {
- mPrimitiveFields.mTranslationY = translationY;
- mPrimitiveFields.mMatrixOrPivotDirty = true;
- }
+ bool setTranslationY(float translationY) {
+ return RP_SET_AND_DIRTY(mPrimitiveFields.mTranslationY, translationY);
}
float getTranslationY() const {
return mPrimitiveFields.mTranslationY;
}
- void setTranslationZ(float translationZ) {
- if (translationZ != mPrimitiveFields.mTranslationZ) {
- mPrimitiveFields.mTranslationZ = translationZ;
- // mMatrixOrPivotDirty not set, since matrix doesn't respect Z
- }
+ bool setTranslationZ(float translationZ) {
+ return RP_SET(mPrimitiveFields.mTranslationZ, translationZ);
+ // mMatrixOrPivotDirty not set, since matrix doesn't respect Z
}
float getTranslationZ() const {
@@ -153,8 +147,8 @@
}
// Animation helper
- void setX(float value) {
- setTranslationX(value - getLeft());
+ bool setX(float value) {
+ return setTranslationX(value - getLeft());
}
// Animation helper
@@ -163,8 +157,8 @@
}
// Animation helper
- void setY(float value) {
- setTranslationY(value - getTop());
+ bool setY(float value) {
+ return setTranslationY(value - getTop());
}
// Animation helper
@@ -173,87 +167,80 @@
}
// Animation helper
- void setZ(float value) {
- setTranslationZ(value - getElevation());
+ bool setZ(float value) {
+ return setTranslationZ(value - getElevation());
}
float getZ() const {
return getElevation() + getTranslationZ();
}
- void setRotation(float rotation) {
- if (rotation != mPrimitiveFields.mRotation) {
- mPrimitiveFields.mRotation = rotation;
- mPrimitiveFields.mMatrixOrPivotDirty = true;
- }
+ bool setRotation(float rotation) {
+ return RP_SET_AND_DIRTY(mPrimitiveFields.mRotation, rotation);
}
float getRotation() const {
return mPrimitiveFields.mRotation;
}
- void setRotationX(float rotationX) {
- if (rotationX != mPrimitiveFields.mRotationX) {
- mPrimitiveFields.mRotationX = rotationX;
- mPrimitiveFields.mMatrixOrPivotDirty = true;
- }
+ bool setRotationX(float rotationX) {
+ return RP_SET_AND_DIRTY(mPrimitiveFields.mRotationX, rotationX);
}
float getRotationX() const {
return mPrimitiveFields.mRotationX;
}
- void setRotationY(float rotationY) {
- if (rotationY != mPrimitiveFields.mRotationY) {
- mPrimitiveFields.mRotationY = rotationY;
- mPrimitiveFields.mMatrixOrPivotDirty = true;
- }
+ bool setRotationY(float rotationY) {
+ return RP_SET_AND_DIRTY(mPrimitiveFields.mRotationY, rotationY);
}
float getRotationY() const {
return mPrimitiveFields.mRotationY;
}
- void setScaleX(float scaleX) {
- if (scaleX != mPrimitiveFields.mScaleX) {
- mPrimitiveFields.mScaleX = scaleX;
- mPrimitiveFields.mMatrixOrPivotDirty = true;
- }
+ bool setScaleX(float scaleX) {
+ return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleX, scaleX);
}
float getScaleX() const {
return mPrimitiveFields.mScaleX;
}
- void setScaleY(float scaleY) {
- if (scaleY != mPrimitiveFields.mScaleY) {
- mPrimitiveFields.mScaleY = scaleY;
- mPrimitiveFields.mMatrixOrPivotDirty = true;
- }
+ bool setScaleY(float scaleY) {
+ return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleY, scaleY);
}
float getScaleY() const {
return mPrimitiveFields.mScaleY;
}
- void setPivotX(float pivotX) {
- mPrimitiveFields.mPivotX = pivotX;
- mPrimitiveFields.mMatrixOrPivotDirty = true;
- mPrimitiveFields.mPivotExplicitlySet = true;
+ bool setPivotX(float pivotX) {
+ if (RP_SET(mPrimitiveFields.mPivotX, pivotX)
+ || !mPrimitiveFields.mPivotExplicitlySet) {
+ mPrimitiveFields.mMatrixOrPivotDirty = true;
+ mPrimitiveFields.mPivotExplicitlySet = true;
+ return true;
+ }
+ return false;
}
/* Note that getPivotX and getPivotY are adjusted by updateMatrix(),
- * so the value returned mPrimitiveFields.may be stale if the RenderProperties has been
- * mPrimitiveFields.modified since the last call to updateMatrix()
+ * so the value returned may be stale if the RenderProperties has been
+ * modified since the last call to updateMatrix()
*/
float getPivotX() const {
return mPrimitiveFields.mPivotX;
}
- void setPivotY(float pivotY) {
- mPrimitiveFields.mPivotY = pivotY;
- mPrimitiveFields.mMatrixOrPivotDirty = true;
- mPrimitiveFields.mPivotExplicitlySet = true;
+ bool setPivotY(float pivotY) {
+ if (RP_SET(mPrimitiveFields.mPivotY, pivotY)
+ || !mPrimitiveFields.mPivotExplicitlySet) {
+ mPrimitiveFields.mMatrixOrPivotDirty = true;
+ mPrimitiveFields.mPivotExplicitlySet = true;
+ return true;
+ }
+ return false;
}
float getPivotY() const {
@@ -264,11 +251,13 @@
return mPrimitiveFields.mPivotExplicitlySet;
}
- void setCameraDistance(float distance) {
+ bool setCameraDistance(float distance) {
if (distance != getCameraDistance()) {
mPrimitiveFields.mMatrixOrPivotDirty = true;
mComputedFields.mTransformCamera.setCameraLocation(0, 0, distance);
+ return true;
}
+ return false;
}
float getCameraDistance() const {
@@ -276,75 +265,73 @@
return const_cast<Sk3DView*>(&mComputedFields.mTransformCamera)->getCameraLocationZ();
}
- void setLeft(int left) {
- if (left != mPrimitiveFields.mLeft) {
- mPrimitiveFields.mLeft = left;
+ bool setLeft(int left) {
+ if (RP_SET(mPrimitiveFields.mLeft, left)) {
mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft;
if (!mPrimitiveFields.mPivotExplicitlySet) {
mPrimitiveFields.mMatrixOrPivotDirty = true;
}
+ return true;
}
+ return false;
}
float getLeft() const {
return mPrimitiveFields.mLeft;
}
- void setTop(int top) {
- if (top != mPrimitiveFields.mTop) {
- mPrimitiveFields.mTop = top;
+ bool setTop(int top) {
+ if (RP_SET(mPrimitiveFields.mTop, top)) {
mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop;
if (!mPrimitiveFields.mPivotExplicitlySet) {
mPrimitiveFields.mMatrixOrPivotDirty = true;
}
+ return true;
}
+ return false;
}
float getTop() const {
return mPrimitiveFields.mTop;
}
- void setRight(int right) {
- if (right != mPrimitiveFields.mRight) {
- mPrimitiveFields.mRight = right;
+ bool setRight(int right) {
+ if (RP_SET(mPrimitiveFields.mRight, right)) {
mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft;
if (!mPrimitiveFields.mPivotExplicitlySet) {
mPrimitiveFields.mMatrixOrPivotDirty = true;
}
+ return true;
}
+ return false;
}
float getRight() const {
return mPrimitiveFields.mRight;
}
- void setBottom(int bottom) {
- if (bottom != mPrimitiveFields.mBottom) {
- mPrimitiveFields.mBottom = bottom;
+ bool setBottom(int bottom) {
+ if (RP_SET(mPrimitiveFields.mBottom, bottom)) {
mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop;
if (!mPrimitiveFields.mPivotExplicitlySet) {
mPrimitiveFields.mMatrixOrPivotDirty = true;
}
+ return true;
}
+ return false;
}
float getBottom() const {
return mPrimitiveFields.mBottom;
}
- void setLeftTop(int left, int top) {
- if (left != mPrimitiveFields.mLeft || top != mPrimitiveFields.mTop) {
- mPrimitiveFields.mLeft = left;
- mPrimitiveFields.mTop = top;
- mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft;
- mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop;
- if (!mPrimitiveFields.mPivotExplicitlySet) {
- mPrimitiveFields.mMatrixOrPivotDirty = true;
- }
- }
+ bool setLeftTop(int left, int top) {
+ bool leftResult = setLeft(left);
+ bool topResult = setTop(top);
+ return leftResult || topResult;
}
- void setLeftTopRightBottom(int left, int top, int right, int bottom) {
+ bool setLeftTopRightBottom(int left, int top, int right, int bottom) {
if (left != mPrimitiveFields.mLeft || top != mPrimitiveFields.mTop
|| right != mPrimitiveFields.mRight || bottom != mPrimitiveFields.mBottom) {
mPrimitiveFields.mLeft = left;
@@ -356,31 +343,47 @@
if (!mPrimitiveFields.mPivotExplicitlySet) {
mPrimitiveFields.mMatrixOrPivotDirty = true;
}
+ return true;
}
+ return false;
}
- void offsetLeftRight(float offset) {
+ bool offsetLeftRight(float offset) {
if (offset != 0) {
mPrimitiveFields.mLeft += offset;
mPrimitiveFields.mRight += offset;
- if (!mPrimitiveFields.mPivotExplicitlySet) {
- mPrimitiveFields.mMatrixOrPivotDirty = true;
- }
+ return true;
}
+ return false;
}
- void offsetTopBottom(float offset) {
+ bool offsetTopBottom(float offset) {
if (offset != 0) {
mPrimitiveFields.mTop += offset;
mPrimitiveFields.mBottom += offset;
- if (!mPrimitiveFields.mPivotExplicitlySet) {
- mPrimitiveFields.mMatrixOrPivotDirty = true;
- }
+ return true;
}
+ return false;
}
- void setCaching(bool caching) {
- mPrimitiveFields.mCaching = caching;
+ bool setScrollX(int scrollX) {
+ return RP_SET(mPrimitiveFields.mScrollX, scrollX);
+ }
+
+ bool setScrollY(int scrollY) {
+ return RP_SET(mPrimitiveFields.mScrollY, scrollY);
+ }
+
+ int getScrollX() const {
+ return mPrimitiveFields.mScrollX;
+ }
+
+ int getScrollY() const {
+ return mPrimitiveFields.mScrollY;
+ }
+
+ bool setCaching(bool caching) {
+ return RP_SET(mPrimitiveFields.mCaching, caching);
}
int getWidth() const {
@@ -478,6 +481,7 @@
float mPivotX, mPivotY;
int mLeft, mTop, mRight, mBottom;
int mWidth, mHeight;
+ int mScrollX, mScrollY;
bool mPivotExplicitlySet;
bool mMatrixOrPivotDirty;
bool mCaching;
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index 8355f83..2096f98 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -18,11 +18,14 @@
#include <utils/Timers.h>
+#include "utils/Macros.h"
+
namespace android {
namespace uirenderer {
class BaseRenderNodeAnimator;
class AnimationListener;
+class DamageAccumulator;
class AnimationHook {
public:
@@ -31,21 +34,44 @@
~AnimationHook() {}
};
-struct TreeInfo {
- // The defaults here should be safe for everyone but DrawFrameTask to use as-is.
- TreeInfo()
- : frameTimeMs(0)
+// This would be a struct, but we want to PREVENT_COPY_AND_ASSIGN
+class TreeInfo {
+ PREVENT_COPY_AND_ASSIGN(TreeInfo);
+public:
+ enum TraversalMode {
+ // The full monty - sync, push, run animators, etc... Used by DrawFrameTask
+ // May only be used if both the UI thread and RT thread are blocked on the
+ // prepare
+ MODE_FULL,
+ // Run only what can be done safely on RT thread. Currently this only means
+ // animators, but potentially things like SurfaceTexture updates
+ // could be handled by this as well if there are no listeners
+ MODE_RT_ONLY,
+ // The subtree is being detached. Maybe. If the RenderNode is present
+ // in both the old and new display list's children then it will get a
+ // MODE_MAYBE_DETACHING followed shortly by a MODE_FULL.
+ // Push any pending display list changes in case it is detached,
+ // but don't evaluate animators and such as if it isn't detached as a
+ // MODE_FULL will follow shortly.
+ MODE_MAYBE_DETACHING,
+ // TODO: TRIM_MEMORY?
+ };
+
+ explicit TreeInfo(TraversalMode mode)
+ : mode(mode)
+ , frameTimeMs(0)
, animationHook(NULL)
- , prepareTextures(false)
- , performStagingPush(true)
- , evaluateAnimations(false)
+ , prepareTextures(mode == MODE_FULL)
+ , damageAccumulator(0)
{}
+ const TraversalMode mode;
nsecs_t frameTimeMs;
AnimationHook* animationHook;
+ // TODO: Remove this? Currently this is used to signal to stop preparing
+ // textures if we run out of cache space.
bool prepareTextures;
- bool performStagingPush;
- bool evaluateAnimations;
+ DamageAccumulator* damageAccumulator;
struct Out {
Out()
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 9ebee1d..8a5c857 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -439,6 +439,7 @@
mRenderThread.removeFrameCallback(this);
info.frameTimeMs = mRenderThread.timeLord().frameTimeMs();
+ info.damageAccumulator = &mDamageAccumulator;
mRootRenderNode->prepareTree(info);
int runningBehind = 0;
@@ -465,27 +466,30 @@
mRenderThread.pushBackFrameCallback(this);
}
-void CanvasContext::draw(Rect* dirty) {
+void CanvasContext::draw() {
LOG_ALWAYS_FATAL_IF(!mCanvas || mEglSurface == EGL_NO_SURFACE,
"drawDisplayList called on a context with no canvas or surface!");
profiler().markPlaybackStart();
+ SkRect dirty;
+ mDamageAccumulator.finish(&dirty);
+
EGLint width, height;
mGlobalContext->beginFrame(mEglSurface, &width, &height);
if (width != mCanvas->getViewportWidth() || height != mCanvas->getViewportHeight()) {
mCanvas->setViewport(width, height);
- dirty = NULL;
+ dirty.setEmpty();
} else if (!mDirtyRegionsEnabled || mHaveNewSurface) {
- dirty = NULL;
+ dirty.setEmpty();
} else {
- profiler().unionDirty(dirty);
+ profiler().unionDirty(&dirty);
}
status_t status;
- if (dirty && !dirty->isEmpty()) {
- status = mCanvas->prepareDirty(dirty->left, dirty->top,
- dirty->right, dirty->bottom, mOpaque);
+ if (!dirty.isEmpty()) {
+ status = mCanvas->prepareDirty(dirty.fLeft, dirty.fTop,
+ dirty.fRight, dirty.fBottom, mOpaque);
} else {
status = mCanvas->prepare(mOpaque);
}
@@ -516,14 +520,12 @@
profiler().startFrame();
- TreeInfo info;
- info.evaluateAnimations = true;
- info.performStagingPush = false;
+ TreeInfo info(TreeInfo::MODE_RT_ONLY);
info.prepareTextures = false;
prepareTree(info);
if (info.out.canDrawThisFrame) {
- draw(NULL);
+ draw();
}
}
@@ -543,7 +545,7 @@
bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
requireGlContext();
- TreeInfo info;
+ TreeInfo info(TreeInfo::MODE_FULL);
layer->apply(info);
return LayerRenderer::copyLayer(layer->backingLayer(), bitmap);
}
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 00c5bf0..d926b38 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -23,6 +23,7 @@
#include <utils/Functor.h>
#include <utils/Vector.h>
+#include "../DamageAccumulator.h"
#include "../DrawProfiler.h"
#include "../RenderNode.h"
#include "RenderTask.h"
@@ -57,7 +58,7 @@
void makeCurrent();
void processLayerUpdate(DeferredLayerUpdater* layerUpdater, TreeInfo& info);
void prepareTree(TreeInfo& info);
- void draw(Rect* dirty);
+ void draw();
void destroyCanvasAndSurface();
// IFrameCallback, Chroreographer-driven frame callback entry point
@@ -99,6 +100,7 @@
bool mOpaque;
OpenGLRenderer* mCanvas;
bool mHaveNewSurface;
+ DamageAccumulator mDamageAccumulator;
const sp<RenderNode> mRootRenderNode;
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 61d67ca..bdfdd21 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -68,10 +68,6 @@
}
}
-void DrawFrameTask::setDirty(int left, int top, int right, int bottom) {
- mDirty.set(left, top, right, bottom);
-}
-
int DrawFrameTask::drawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos) {
LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!");
@@ -83,7 +79,6 @@
// Reset the single-frame data
mFrameTimeNanos = 0;
mRecordDurationNanos = 0;
- mDirty.setEmpty();
return mSyncResult;
}
@@ -103,13 +98,12 @@
bool canUnblockUiThread;
bool canDrawThisFrame;
{
- TreeInfo info;
+ TreeInfo info(TreeInfo::MODE_FULL);
canUnblockUiThread = syncFrameState(info);
canDrawThisFrame = info.out.canDrawThisFrame;
}
// Grab a copy of everything we need
- Rect dirty(mDirty);
CanvasContext* context = mContext;
// From this point on anything in "this" is *UNSAFE TO ACCESS*
@@ -118,7 +112,7 @@
}
if (CC_LIKELY(canDrawThisFrame)) {
- context->draw(&dirty);
+ context->draw();
}
if (!canUnblockUiThread) {
@@ -126,18 +120,11 @@
}
}
-static void initTreeInfo(TreeInfo& info) {
- info.prepareTextures = true;
- info.performStagingPush = true;
- info.evaluateAnimations = true;
-}
-
bool DrawFrameTask::syncFrameState(TreeInfo& info) {
ATRACE_CALL();
mRenderThread->timeLord().vsyncReceived(mFrameTimeNanos);
mContext->makeCurrent();
Caches::getInstance().textureCache.resetMarkInUse();
- initTreeInfo(info);
for (size_t i = 0; i < mLayers.size(); i++) {
mContext->processLayerUpdate(mLayers[i].get(), info);
@@ -149,8 +136,6 @@
mContext->prepareTree(info);
if (info.out.hasAnimations) {
- // TODO: dirty calculations, for now just do a full-screen inval
- mDirty.setEmpty();
if (info.out.requiresUiRedraw) {
mSyncResult |= kSync_UIRedrawRequired;
}
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index d4129b6..96f0add 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -60,7 +60,6 @@
void pushLayerUpdate(DeferredLayerUpdater* layer);
void removeLayerUpdate(DeferredLayerUpdater* layer);
- void setDirty(int left, int top, int right, int bottom);
void setDensity(float density) { mDensity = density; }
int drawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos);
@@ -80,7 +79,6 @@
/*********************************************
* Single frame data
*********************************************/
- Rect mDirty;
nsecs_t mFrameTimeNanos;
nsecs_t mRecordDurationNanos;
float mDensity;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 0901963..ded10a1 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -180,8 +180,7 @@
}
int RenderProxy::syncAndDrawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos,
- float density, int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom) {
- mDrawFrameTask.setDirty(dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
+ float density) {
mDrawFrameTask.setDensity(density);
return mDrawFrameTask.drawFrame(frameTimeNanos, recordDurationNanos);
}
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 944ff9c..a95f8f0 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -70,7 +70,7 @@
ANDROID_API void setup(int width, int height, const Vector3& lightCenter, float lightRadius);
ANDROID_API void setOpaque(bool opaque);
ANDROID_API int syncAndDrawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos,
- float density, int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
+ float density);
ANDROID_API void destroyCanvasAndSurface();
ANDROID_API void invokeFunctor(Functor* functor, bool waitForCompletion);