Merge "3d view system!"

This commit is contained in:
Chris Craik
2013-12-13 21:55:49 +00:00
committed by Android (Google) Code Review
18 changed files with 667 additions and 142 deletions

View File

@@ -437,6 +437,21 @@ public abstract class DisplayList {
*/
public abstract float getTranslationY();
/**
* Sets the translation value for the display list on the Z axis
*
* @see View#setTranslationZ(float)
* @see #getTranslationZ()
*/
public abstract void setTranslationZ(float translationZ);
/**
* Returns the translation value for this display list on the Z axis.
*
* @see #setTranslationZ(float)
*/
public abstract float getTranslationZ();
/**
* Sets the rotation value for the display list around the Z axis
*
@@ -536,7 +551,8 @@ public abstract class DisplayList {
*
* @hide
*/
public abstract void setTransformationInfo(float alpha, float translationX, float translationY,
public abstract void setTransformationInfo(float alpha,
float translationX, float translationY, float translationZ,
float rotation, float rotationX, float rotationY, float scaleX, float scaleY);
/**

View File

@@ -230,6 +230,21 @@ class GLES20DisplayList extends DisplayList {
return 0.0f;
}
@Override
public void setTranslationZ(float translationZ) {
if (hasNativeDisplayList()) {
nSetTranslationZ(mFinalizer.mNativeDisplayList, translationZ);
}
}
@Override
public float getTranslationZ() {
if (hasNativeDisplayList()) {
return nGetTranslationZ(mFinalizer.mNativeDisplayList);
}
return 0.0f;
}
@Override
public void setRotation(float rotation) {
if (hasNativeDisplayList()) {
@@ -306,10 +321,12 @@ class GLES20DisplayList extends DisplayList {
}
@Override
public void setTransformationInfo(float alpha, float translationX, float translationY,
public void setTransformationInfo(float alpha,
float translationX, float translationY, float translationZ,
float rotation, float rotationX, float rotationY, float scaleX, float scaleY) {
if (hasNativeDisplayList()) {
nSetTransformationInfo(mFinalizer.mNativeDisplayList, alpha, translationX, translationY,
nSetTransformationInfo(mFinalizer.mNativeDisplayList, alpha,
translationX, translationY, translationZ,
rotation, rotationX, rotationY, scaleX, scaleY);
}
}
@@ -466,14 +483,15 @@ class GLES20DisplayList extends DisplayList {
boolean hasOverlappingRendering);
private static native void nSetTranslationX(int displayList, float translationX);
private static native void nSetTranslationY(int displayList, float translationY);
private static native void nSetTranslationZ(int displayList, float translationZ);
private static native void nSetRotation(int displayList, float rotation);
private static native void nSetRotationX(int displayList, float rotationX);
private static native void nSetRotationY(int displayList, float rotationY);
private static native void nSetScaleX(int displayList, float scaleX);
private static native void nSetScaleY(int displayList, float scaleY);
private static native void nSetTransformationInfo(int displayList, float alpha,
float translationX, float translationY, float rotation, float rotationX,
float rotationY, float scaleX, float scaleY);
float translationX, float translationY, float translationZ,
float rotation, float rotationX, float rotationY, float scaleX, float scaleY);
private static native void nSetStaticMatrix(int displayList, int nativeMatrix);
private static native void nSetAnimationMatrix(int displayList, int animationMatrix);
@@ -489,6 +507,7 @@ class GLES20DisplayList extends DisplayList {
private static native float nGetScaleY(int displayList);
private static native float nGetTranslationX(int displayList);
private static native float nGetTranslationY(int displayList);
private static native float nGetTranslationZ(int displayList);
private static native float nGetRotation(int displayList);
private static native float nGetRotationX(int displayList);
private static native float nGetRotationY(int displayList);

View File

@@ -2981,6 +2981,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
@ViewDebug.ExportedProperty
float mTranslationY = 0f;
@ViewDebug.ExportedProperty
float mTranslationZ = 0f;
/**
* The amount of scale in the x direction around the pivot point. A
* value of 1 means no scaling is applied.
@@ -10507,6 +10510,35 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
}
/**
* @hide
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getTranslationZ() {
return mTransformationInfo != null ? mTransformationInfo.mTranslationZ : 0;
}
/**
* @hide
*/
public void setTranslationZ(float translationZ) {
ensureTransformationInfo();
final TransformationInfo info = mTransformationInfo;
if (info.mTranslationZ != translationZ) {
invalidateViewProperty(true, false);
info.mTranslationZ = translationZ;
info.mMatrixDirty = true;
invalidateViewProperty(false, true);
if (mDisplayList != null) {
mDisplayList.setTranslationZ(translationZ);
}
if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
// View was rejected last time it was drawn by its parent; this may have changed
invalidateParentIfNeeded();
}
}
}
/**
* Hit rectangle in parent's coordinates
*
@@ -14173,6 +14205,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
displayList.setTransformationInfo(alpha,
mTransformationInfo.mTranslationX, mTransformationInfo.mTranslationY,
mTransformationInfo.mTranslationZ,
mTransformationInfo.mRotation, mTransformationInfo.mRotationX,
mTransformationInfo.mRotationY, mTransformationInfo.mScaleX,
mTransformationInfo.mScaleY);

View File

@@ -144,9 +144,10 @@ public class ViewPropertyAnimator {
private static final int X = 0x0080;
private static final int Y = 0x0100;
private static final int ALPHA = 0x0200;
private static final int TRANSLATION_Z = 0x0400;
private static final int TRANSFORM_MASK = TRANSLATION_X | TRANSLATION_Y | SCALE_X | SCALE_Y |
ROTATION | ROTATION_X | ROTATION_Y | X | Y;
private static final int TRANSFORM_MASK = TRANSLATION_X | TRANSLATION_Y | TRANSLATION_Z |
SCALE_X | SCALE_Y | ROTATION | ROTATION_X | ROTATION_Y | X | Y;
/**
* The mechanism by which the user can request several properties that are then animated
@@ -572,6 +573,22 @@ public class ViewPropertyAnimator {
return this;
}
/**
* @hide
*/
public ViewPropertyAnimator translationZ(float value) {
animateProperty(TRANSLATION_Z, value);
return this;
}
/**
* @hide
*/
public ViewPropertyAnimator translationZBy(float value) {
animatePropertyBy(TRANSLATION_Z, value);
return this;
}
/**
* This method will cause the View's <code>translationY</code> property to be animated to the
* specified value. Animations already running on the property will be canceled.
@@ -909,6 +926,10 @@ public class ViewPropertyAnimator {
info.mTranslationY = value;
if (displayList != null) displayList.setTranslationY(value);
break;
case TRANSLATION_Z:
info.mTranslationZ = value;
if (displayList != null) displayList.setTranslationZ(value);
break;
case ROTATION:
info.mRotation = value;
if (displayList != null) displayList.setRotation(value);
@@ -957,6 +978,8 @@ public class ViewPropertyAnimator {
return info.mTranslationX;
case TRANSLATION_Y:
return info.mTranslationY;
case TRANSLATION_Z:
return info.mTranslationZ;
case ROTATION:
return info.mRotation;
case ROTATION_X:

View File

@@ -114,6 +114,11 @@ static void android_view_GLES20DisplayList_setTranslationY(JNIEnv* env,
displayList->setTranslationY(ty);
}
static void android_view_GLES20DisplayList_setTranslationZ(JNIEnv* env,
jobject clazz, DisplayList* displayList, float tz) {
displayList->setTranslationZ(tz);
}
static void android_view_GLES20DisplayList_setRotation(JNIEnv* env,
jobject clazz, DisplayList* displayList, float rotation) {
displayList->setRotation(rotation);
@@ -141,11 +146,12 @@ static void android_view_GLES20DisplayList_setScaleY(JNIEnv* env,
static void android_view_GLES20DisplayList_setTransformationInfo(JNIEnv* env,
jobject clazz, DisplayList* displayList, float alpha,
float translationX, float translationY, float rotation, float rotationX, float rotationY,
float scaleX, float scaleY) {
float translationX, float translationY, float translationZ,
float rotation, float rotationX, float rotationY, float scaleX, float scaleY) {
displayList->setAlpha(alpha);
displayList->setTranslationX(translationX);
displayList->setTranslationY(translationY);
displayList->setTranslationZ(translationZ);
displayList->setRotation(rotation);
displayList->setRotationX(rotationX);
displayList->setRotationY(rotationY);
@@ -320,12 +326,13 @@ static JNINativeMethod gMethods[] = {
(void*) android_view_GLES20DisplayList_setHasOverlappingRendering },
{ "nSetTranslationX", "(IF)V", (void*) android_view_GLES20DisplayList_setTranslationX },
{ "nSetTranslationY", "(IF)V", (void*) android_view_GLES20DisplayList_setTranslationY },
{ "nSetTranslationZ", "(IF)V", (void*) android_view_GLES20DisplayList_setTranslationZ },
{ "nSetRotation", "(IF)V", (void*) android_view_GLES20DisplayList_setRotation },
{ "nSetRotationX", "(IF)V", (void*) android_view_GLES20DisplayList_setRotationX },
{ "nSetRotationY", "(IF)V", (void*) android_view_GLES20DisplayList_setRotationY },
{ "nSetScaleX", "(IF)V", (void*) android_view_GLES20DisplayList_setScaleX },
{ "nSetScaleY", "(IF)V", (void*) android_view_GLES20DisplayList_setScaleY },
{ "nSetTransformationInfo","(IFFFFFFFF)V",
{ "nSetTransformationInfo","(IFFFFFFFFF)V",
(void*) android_view_GLES20DisplayList_setTransformationInfo },
{ "nSetPivotX", "(IF)V", (void*) android_view_GLES20DisplayList_setPivotX },
{ "nSetPivotY", "(IF)V", (void*) android_view_GLES20DisplayList_setPivotY },

View File

@@ -85,6 +85,9 @@
// Turn on to highlight drawing batches and merged batches with different colors
#define DEBUG_MERGE_BEHAVIOR 0
// Turn on to enable 3D support in the renderer (off by default until API for control exists)
#define DEBUG_ENABLE_3D 0
#if DEBUG_INIT
#define INIT_LOGD(...) ALOGD(__VA_ARGS__)
#else

View File

@@ -79,13 +79,13 @@ public:
};
class DeferredDisplayList {
friend class DeferStateStruct; // used to give access to allocator
public:
DeferredDisplayList(const Rect& bounds, bool avoidOverdraw = true) :
mBounds(bounds), mAvoidOverdraw(avoidOverdraw) {
clear();
}
~DeferredDisplayList() { clear(); }
void reset(const Rect& bounds) { mBounds.set(bounds); }
enum OpBatchId {
kOpBatch_None = 0, // Don't batch
@@ -120,6 +120,8 @@ public:
void addDrawOp(OpenGLRenderer& renderer, DrawOp* op);
private:
DeferredDisplayList(const DeferredDisplayList& other); // disallow copy
DeferredDisplayState* createState() {
return new (mAllocator) DeferredDisplayState();
}

View File

@@ -14,8 +14,12 @@
* limitations under the License.
*/
#define ATRACE_TAG ATRACE_TAG_VIEW
#include <SkCanvas.h>
#include <utils/Trace.h>
#include "Debug.h"
#include "DisplayList.h"
#include "DisplayListOp.h"
@@ -65,11 +69,6 @@ void DisplayList::destroyDisplayListDeferred(DisplayList* displayList) {
void DisplayList::clearResources() {
mDisplayListData = NULL;
mClipRectOp = NULL;
mSaveLayerOp = NULL;
mSaveOp = NULL;
mRestoreToCountOp = NULL;
delete mTransformMatrix;
delete mTransformCamera;
delete mTransformMatrix3D;
@@ -168,17 +167,6 @@ void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorde
return;
}
// allocate reusable ops for state-deferral
LinearAllocator& alloc = mDisplayListData->allocator;
mClipRectOp = new (alloc) ClipRectOp();
mSaveLayerOp = new (alloc) SaveLayerOp();
mSaveOp = new (alloc) SaveOp();
mRestoreToCountOp = new (alloc) RestoreToCountOp();
if (CC_UNLIKELY(!mSaveOp)) { // temporary debug logging
ALOGW("Error: %s's SaveOp not allocated, size %d", getName(), mSize);
CRASH();
}
mFunctorCount = recorder.getFunctorCount();
Caches& caches = Caches::getInstance();
@@ -253,6 +241,7 @@ void DisplayList::init() {
mHasOverlappingRendering = true;
mTranslationX = 0;
mTranslationY = 0;
mTranslationZ = 0;
mRotation = 0;
mRotationX = 0;
mRotationY= 0;
@@ -269,6 +258,7 @@ void DisplayList::init() {
mHeight = 0;
mPivotExplicitlySet = false;
mCaching = false;
mIs3dRoot = true; // TODO: setter, java side impl
}
size_t DisplayList::getSize() {
@@ -320,27 +310,38 @@ void DisplayList::updateMatrix() {
mPivotY = mPrevHeight / 2.0f;
}
}
if ((mMatrixFlags & ROTATION_3D) == 0) {
if (!DEBUG_ENABLE_3D && (mMatrixFlags & ROTATION_3D) == 0) {
mTransformMatrix->setTranslate(mTranslationX, mTranslationY);
mTransformMatrix->preRotate(mRotation, mPivotX, mPivotY);
mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY);
} else {
if (!mTransformCamera) {
mTransformCamera = new Sk3DView();
mTransformMatrix3D = new SkMatrix();
if (DEBUG_ENABLE_3D) {
mTransform.loadTranslate(mPivotX + mTranslationX, mPivotY + mTranslationY,
mTranslationZ);
mTransform.rotate(mRotationX, 1, 0, 0);
mTransform.rotate(mRotationY, 0, 1, 0);
mTransform.rotate(mRotation, 0, 0, 1);
mTransform.scale(mScaleX, mScaleY, 1);
mTransform.translate(-mPivotX, -mPivotY);
} else {
/* TODO: support this old transform approach, based on API level */
if (!mTransformCamera) {
mTransformCamera = new Sk3DView();
mTransformMatrix3D = new SkMatrix();
}
mTransformMatrix->reset();
mTransformCamera->save();
mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY);
mTransformCamera->rotateX(mRotationX);
mTransformCamera->rotateY(mRotationY);
mTransformCamera->rotateZ(-mRotation);
mTransformCamera->getMatrix(mTransformMatrix3D);
mTransformMatrix3D->preTranslate(-mPivotX, -mPivotY);
mTransformMatrix3D->postTranslate(mPivotX + mTranslationX,
mPivotY + mTranslationY);
mTransformMatrix->postConcat(*mTransformMatrix3D);
mTransformCamera->restore();
}
mTransformMatrix->reset();
mTransformCamera->save();
mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY);
mTransformCamera->rotateX(mRotationX);
mTransformCamera->rotateY(mRotationY);
mTransformCamera->rotateZ(-mRotation);
mTransformCamera->getMatrix(mTransformMatrix3D);
mTransformMatrix3D->preTranslate(-mPivotX, -mPivotY);
mTransformMatrix3D->postTranslate(mPivotX + mTranslationX,
mPivotY + mTranslationY);
mTransformMatrix->postConcat(*mTransformMatrix3D);
mTransformCamera->restore();
}
}
mMatrixDirty = false;
@@ -417,8 +418,13 @@ void DisplayList::setViewProperties(OpenGLRenderer& renderer, T& handler,
if (mMatrixFlags != 0) {
if (mMatrixFlags == TRANSLATION) {
renderer.translate(mTranslationX, mTranslationY);
renderer.translateZ(mTranslationZ);
} else {
#if DEBUG_ENABLE_3D
renderer.concatMatrix(mTransform);
#else
renderer.concatMatrix(mTransformMatrix);
#endif
}
}
bool clipToBoundsNeeded = mCaching ? false : mClipToBounds;
@@ -436,14 +442,107 @@ void DisplayList::setViewProperties(OpenGLRenderer& renderer, T& handler,
saveFlags |= SkCanvas::kClipToLayer_SaveFlag;
clipToBoundsNeeded = false; // clipping done by saveLayer
}
handler(mSaveLayerOp->reinit(0, 0, mRight - mLeft, mBottom - mTop,
mAlpha * 255, SkXfermode::kSrcOver_Mode, saveFlags), PROPERTY_SAVECOUNT,
mClipToBounds);
SaveLayerOp* op = new (handler.allocator()) SaveLayerOp(
0, 0, mRight - mLeft, mBottom - mTop,
mAlpha * 255, SkXfermode::kSrcOver_Mode, saveFlags);
handler(op, PROPERTY_SAVECOUNT, mClipToBounds);
}
}
if (clipToBoundsNeeded) {
handler(mClipRectOp->reinit(0, 0, mRight - mLeft, mBottom - mTop, SkRegion::kIntersect_Op),
PROPERTY_SAVECOUNT, mClipToBounds);
ClipRectOp* op = new (handler.allocator()) ClipRectOp(0, 0,
mRight - mLeft, mBottom - mTop, SkRegion::kIntersect_Op);
handler(op, PROPERTY_SAVECOUNT, mClipToBounds);
}
}
/**
* Apply property-based transformations to input matrix
*/
void DisplayList::applyViewPropertyTransforms(mat4& matrix) {
if (mLeft != 0 || mTop != 0) {
matrix.translate(mLeft, mTop);
}
if (mStaticMatrix) {
mat4 stat(*mStaticMatrix);
matrix.multiply(stat);
} else if (mAnimationMatrix) {
mat4 anim(*mAnimationMatrix);
matrix.multiply(anim);
}
if (mMatrixFlags != 0) {
if (mMatrixFlags == TRANSLATION) {
matrix.translate(mTranslationX, mTranslationY, mTranslationZ);
} else {
#if DEBUG_ENABLE_3D
matrix.multiply(mTransform);
#else
mat4 temp(*mTransformMatrix);
matrix.multiply(temp);
#endif
}
}
}
/**
* Organizes the DisplayList hierarchy to prepare for Z-based draw order.
*
* This should be called before a call to defer() or drawDisplayList()
*
* Each DisplayList that serves as a 3d root builds its list of composited children,
* which are flagged to not draw in the standard draw loop.
*/
void DisplayList::computeOrdering() {
ATRACE_CALL();
mat4::identity();
for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) {
DrawDisplayListOp* childOp = mDisplayListData->children[i];
childOp->mDisplayList->computeOrderingImpl(childOp, &m3dNodes, &mat4::identity());
}
}
void DisplayList::computeOrderingImpl(
DrawDisplayListOp* opState,
KeyedVector<float, Vector<DrawDisplayListOp*> >* compositedChildrenOf3dRoot,
const mat4* transformFrom3dRoot) {
// TODO: should avoid this calculation in most cases
opState->mTransformFrom3dRoot.load(*transformFrom3dRoot);
opState->mTransformFrom3dRoot.multiply(opState->mTransformFromParent);
if (mTranslationZ != 0.0f) { // TODO: other signals, such as custom 4x4 matrix
// composited layer, insert into current 3d root and flag for out of order draw
opState->mSkipInOrderDraw = true;
Vector3 pivot(mPivotX, mPivotY, 0.0f);
mat4 totalTransform(opState->mTransformFrom3dRoot);
applyViewPropertyTransforms(totalTransform);
totalTransform.mapPoint3d(pivot);
const float key = pivot.z;
if (compositedChildrenOf3dRoot->indexOfKey(key) < 0) {
compositedChildrenOf3dRoot->add(key, Vector<DrawDisplayListOp*>());
}
compositedChildrenOf3dRoot->editValueFor(key).push(opState);
} else {
// standard in order draw
opState->mSkipInOrderDraw = false;
}
m3dNodes.clear();
if (mIs3dRoot) {
// create a new 3d space for children by separating their ordering
compositedChildrenOf3dRoot = &m3dNodes;
transformFrom3dRoot = &mat4::identity();
} else {
transformFrom3dRoot = &(opState->mTransformFrom3dRoot);
}
if (mDisplayListData->children.size() > 0) {
for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) {
DrawDisplayListOp* childOp = mDisplayListData->children[i];
childOp->mDisplayList->computeOrderingImpl(childOp,
compositedChildrenOf3dRoot, transformFrom3dRoot);
}
}
}
@@ -454,6 +553,8 @@ public:
inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) {
operation->defer(mDeferStruct, saveCount, mLevel, clipToBounds);
}
inline LinearAllocator& allocator() { return *(mDeferStruct.mAllocator); }
private:
DeferStateStruct& mDeferStruct;
const int mLevel;
@@ -474,6 +575,8 @@ public:
#endif
operation->replay(mReplayStruct, saveCount, mLevel, clipToBounds);
}
inline LinearAllocator& allocator() { return *(mReplayStruct.mAllocator); }
private:
ReplayStateStruct& mReplayStruct;
const int mLevel;
@@ -490,11 +593,60 @@ void DisplayList::replay(ReplayStateStruct& replayStruct, const int level) {
replayStruct.mDrawGlStatus);
}
template <class T>
void DisplayList::iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& renderer,
T& handler, const int level) {
if (m3dNodes.size() == 0 ||
(mode == kNegativeZChildren && m3dNodes.keyAt(0) > 0.0f) ||
(mode == kPositiveZChildren && m3dNodes.keyAt(m3dNodes.size() - 1) < 0.0f)) {
// nothing to draw
return;
}
LinearAllocator& alloc = handler.allocator();
ClipRectOp* op = new (alloc) ClipRectOp(0, 0, mWidth, mHeight,
SkRegion::kIntersect_Op); // clip to 3d root bounds for now
handler(op, PROPERTY_SAVECOUNT, mClipToBounds);
int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
for (int i = 0; i < m3dNodes.size(); i++) {
const float zValue = m3dNodes.keyAt(i);
if (mode == kPositiveZChildren && zValue < 0.0f) continue;
if (mode == kNegativeZChildren && zValue > 0.0f) break;
const Vector<DrawDisplayListOp*>& nodesAtZ = m3dNodes[i];
for (int j = 0; j < nodesAtZ.size(); j++) {
DrawDisplayListOp* op = nodesAtZ[j];
if (mode == kPositiveZChildren) {
/* draw shadow on renderer with parent matrix applied, passing in the child's total matrix
*
* TODO:
* -determine and pass background shape (and possibly drawable alpha)
* -view must opt-in to shadows
* -consider shadows for other content
*/
mat4 shadowMatrix(op->mTransformFrom3dRoot);
op->mDisplayList->applyViewPropertyTransforms(shadowMatrix);
DisplayListOp* shadowOp = new (alloc) DrawShadowOp(shadowMatrix, op->mDisplayList->mAlpha,
op->mDisplayList->getWidth(), op->mDisplayList->getHeight());
handler(shadowOp, PROPERTY_SAVECOUNT, mClipToBounds);
}
renderer.concatMatrix(op->mTransformFrom3dRoot);
op->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone
handler(op, renderer.getSaveCount() - 1, mClipToBounds);
op->mSkipInOrderDraw = true;
}
}
handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, mClipToBounds);
}
/**
* This function serves both defer and replay modes, and will organize the displayList's component
* operations for a single frame:
*
* Every 'simple' operation that affects just the matrix and alpha (or other factors of
* Every 'simple' state operation that affects just the matrix and alpha (or other factors of
* DeferredDisplayState) may be issued directly to the renderer, but complex operations (with custom
* defer logic) and operations in displayListOps are issued through the 'handler' which handles the
* defer vs replay logic, per operation
@@ -517,8 +669,9 @@ void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level)
clipRect->right, clipRect->bottom);
#endif
LinearAllocator& alloc = handler.allocator();
int restoreTo = renderer.getSaveCount();
handler(mSaveOp->reinit(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag),
handler(new (alloc) SaveOp(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag),
PROPERTY_SAVECOUNT, mClipToBounds);
DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "",
@@ -526,30 +679,31 @@ void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level)
setViewProperties<T>(renderer, handler, level + 1);
if (mClipToBounds && renderer.quickRejectConservative(0, 0, mWidth, mHeight)) {
DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
handler(mRestoreToCountOp->reinit(restoreTo), PROPERTY_SAVECOUNT, mClipToBounds);
renderer.restoreToCount(restoreTo);
renderer.setOverrideLayerAlpha(1.0f);
return;
}
bool quickRejected = mClipToBounds && renderer.quickRejectConservative(0, 0, mWidth, mHeight);
if (!quickRejected) {
// for 3d root, draw children with negative z values
iterate3dChildren(kNegativeZChildren, renderer, handler, level);
DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
int saveCount = renderer.getSaveCount() - 1;
for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
DisplayListOp *op = mDisplayListData->displayListOps[i];
DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
const int saveCountOffset = renderer.getSaveCount() - 1;
for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
DisplayListOp *op = mDisplayListData->displayListOps[i];
#if DEBUG_DISPLAY_LIST
op->output(level + 1);
op->output(level + 1);
#endif
logBuffer.writeCommand(level, op->name());
handler(op, saveCount, mClipToBounds);
logBuffer.writeCommand(level, op->name());
handler(op, saveCountOffset, mClipToBounds);
}
// for 3d root, draw children with positive z values
iterate3dChildren(kPositiveZChildren, renderer, handler, level);
}
DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
handler(mRestoreToCountOp->reinit(restoreTo), PROPERTY_SAVECOUNT, mClipToBounds);
renderer.restoreToCount(restoreTo);
handler(new (alloc) RestoreToCountOp(restoreTo),
PROPERTY_SAVECOUNT, mClipToBounds);
renderer.setOverrideLayerAlpha(1.0f);
}

View File

@@ -26,6 +26,7 @@
#include <private/hwui/DrawGlInfo.h>
#include <utils/KeyedVector.h>
#include <utils/LinearAllocator.h>
#include <utils/RefBase.h>
#include <utils/SortedVector.h>
@@ -37,6 +38,8 @@
#include <androidfw/ResourceTypes.h>
#include "Debug.h"
#include "Matrix.h"
#include "DeferredDisplayList.h"
#define TRANSLATION 0x0001
#define ROTATION 0x0002
@@ -65,36 +68,70 @@ class ClipRectOp;
class SaveLayerOp;
class SaveOp;
class RestoreToCountOp;
class DrawDisplayListOp;
struct DeferStateStruct {
DeferStateStruct(DeferredDisplayList& deferredList, OpenGLRenderer& renderer, int replayFlags)
: mDeferredList(deferredList), mRenderer(renderer), mReplayFlags(replayFlags) {}
DeferredDisplayList& mDeferredList;
/**
* Holds data used in the playback a tree of DisplayLists.
*/
class PlaybackStateStruct {
protected:
PlaybackStateStruct(OpenGLRenderer& renderer, int replayFlags, LinearAllocator* allocator)
: mRenderer(renderer), mReplayFlags(replayFlags), mAllocator(allocator){}
public:
OpenGLRenderer& mRenderer;
const int mReplayFlags;
// Allocator with the lifetime of a single frame.
// replay uses an Allocator owned by the struct, while defer shares the DeferredDisplayList's Allocator
LinearAllocator * const mAllocator;
};
struct ReplayStateStruct {
class DeferStateStruct : public PlaybackStateStruct {
public:
DeferStateStruct(DeferredDisplayList& deferredList, OpenGLRenderer& renderer, int replayFlags)
: PlaybackStateStruct(renderer, replayFlags, &(deferredList.mAllocator)), mDeferredList(deferredList) {}
DeferredDisplayList& mDeferredList;
};
class ReplayStateStruct : public PlaybackStateStruct {
public:
ReplayStateStruct(OpenGLRenderer& renderer, Rect& dirty, int replayFlags)
: mRenderer(renderer), mDirty(dirty), mReplayFlags(replayFlags),
mDrawGlStatus(DrawGlInfo::kStatusDone) {}
OpenGLRenderer& mRenderer;
: PlaybackStateStruct(renderer, replayFlags, &mReplayAllocator),
mDirty(dirty), mDrawGlStatus(DrawGlInfo::kStatusDone) {}
Rect& mDirty;
const int mReplayFlags;
status_t mDrawGlStatus;
LinearAllocator mReplayAllocator;
};
/**
* Refcounted structure that holds data used in display list stream
* Refcounted structure that holds the list of commands used in display list stream.
*/
class DisplayListData : public LightRefBase<DisplayListData> {
public:
// allocator into which all ops were allocated
LinearAllocator allocator;
// pointers to all ops within display list, pointing into allocator data
Vector<DisplayListOp*> displayListOps;
// list of children display lists for quick, non-drawing traversal
Vector<DrawDisplayListOp*> children;
};
/**
* Replays recorded drawing commands.
* Primary class for storing recorded canvas commands, as well as per-View/ViewGroup display properties.
*
* Recording of canvas commands is somewhat similar to SkPicture, except the canvas-recording
* functionality is split between DisplayListRenderer (which manages the recording), DisplayListData
* (which holds the actual data), and DisplayList (which holds properties and performs playback onto
* a renderer).
*
* Note that DisplayListData is swapped out from beneath an individual DisplayList when a view's
* recorded stream of canvas operations is refreshed. The DisplayList (and its properties) stay
* attached.
*/
class DisplayList {
public:
@@ -113,6 +150,7 @@ public:
void initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing = false);
void computeOrdering();
void defer(DeferStateStruct& deferStruct, const int level);
void replay(ReplayStateStruct& replayStruct, const int level);
@@ -188,12 +226,7 @@ public:
void setTranslationX(float translationX) {
if (translationX != mTranslationX) {
mTranslationX = translationX;
mMatrixDirty = true;
if (mTranslationX == 0.0f && mTranslationY == 0.0f) {
mMatrixFlags &= ~TRANSLATION;
} else {
mMatrixFlags |= TRANSLATION;
}
onTranslationUpdate();
}
}
@@ -204,12 +237,7 @@ public:
void setTranslationY(float translationY) {
if (translationY != mTranslationY) {
mTranslationY = translationY;
mMatrixDirty = true;
if (mTranslationX == 0.0f && mTranslationY == 0.0f) {
mMatrixFlags &= ~TRANSLATION;
} else {
mMatrixFlags |= TRANSLATION;
}
onTranslationUpdate();
}
}
@@ -217,6 +245,17 @@ public:
return mTranslationY;
}
void setTranslationZ(float translationZ) {
if (translationZ != mTranslationZ) {
mTranslationZ = translationZ;
onTranslationUpdate();
}
}
float getTranslationZ() const {
return mTranslationZ;
}
void setRotation(float rotation) {
if (rotation != mRotation) {
mRotation = rotation;
@@ -454,11 +493,35 @@ public:
}
private:
enum ChildrenSelectMode {
kNegativeZChildren,
kPositiveZChildren
};
void onTranslationUpdate() {
mMatrixDirty = true;
if (mTranslationX == 0.0f && mTranslationY == 0.0f && mTranslationZ == 0.0f) {
mMatrixFlags &= ~TRANSLATION;
} else {
mMatrixFlags |= TRANSLATION;
}
}
void outputViewProperties(const int level);
void applyViewPropertyTransforms(mat4& matrix);
void computeOrderingImpl(DrawDisplayListOp* opState,
KeyedVector<float, Vector<DrawDisplayListOp*> >* compositedChildrenOf3dRoot,
const mat4* transformFromRoot);
template <class T>
inline void setViewProperties(OpenGLRenderer& renderer, T& handler, const int level);
template <class T>
inline void iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& renderer,
T& handler, const int level);
template <class T>
inline void iterate(OpenGLRenderer& renderer, T& handler, const int level);
@@ -509,7 +572,7 @@ private:
bool mClipToBounds;
float mAlpha;
bool mHasOverlappingRendering;
float mTranslationX, mTranslationY;
float mTranslationX, mTranslationY, mTranslationZ;
float mRotation, mRotationX, mRotationY;
float mScaleX, mScaleY;
float mPivotX, mPivotY;
@@ -526,23 +589,17 @@ private:
SkMatrix* mTransformMatrix3D;
SkMatrix* mStaticMatrix;
SkMatrix* mAnimationMatrix;
Matrix4 mTransform;
bool mCaching;
bool mIs3dRoot;
/**
* State operations - needed to defer displayList property operations (for example, when setting
* an alpha causes a SaveLayerAlpha to occur). These operations point into mDisplayListData's
* allocation, or null if uninitialized.
*
* These are initialized (via friend re-constructors) when a displayList is issued in either
* replay or deferred mode. If replaying, the ops are not used until the next frame. If
* deferring, the ops may be stored in the DeferredDisplayList to be played back a second time.
*
* They should be used at most once per frame (one call to 'iterate') to avoid overwriting data
* Draw time state - these properties are only set and used during rendering
*/
ClipRectOp* mClipRectOp;
SaveLayerOp* mSaveLayerOp;
SaveOp* mSaveOp;
RestoreToCountOp* mRestoreToCountOp;
// for 3d roots, contains a z sorted list of all children items
KeyedVector<float, Vector<DrawDisplayListOp*> > m3dNodes; // TODO: good data structure
}; // class DisplayList
}; // namespace uirenderer

View File

@@ -262,7 +262,6 @@ protected:
///////////////////////////////////////////////////////////////////////////////
class SaveOp : public StateOp {
friend class DisplayList; // give DisplayList private constructor/reinit access
public:
SaveOp(int flags)
: mFlags(flags) {}
@@ -295,7 +294,6 @@ private:
};
class RestoreToCountOp : public StateOp {
friend class DisplayList; // give DisplayList private constructor/reinit access
public:
RestoreToCountOp(int count)
: mCount(count) {}
@@ -328,7 +326,6 @@ private:
};
class SaveLayerOp : public StateOp {
friend class DisplayList; // give DisplayList private constructor/reinit access
public:
SaveLayerOp(float left, float top, float right, float bottom,
int alpha, SkXfermode::Mode mode, int flags)
@@ -524,7 +521,6 @@ protected:
};
class ClipRectOp : public ClipOp {
friend class DisplayList; // give DisplayList private constructor/reinit access
public:
ClipRectOp(float left, float top, float right, float bottom, SkRegion::Op op)
: ClipOp(op), mArea(left, top, right, bottom) {}
@@ -1100,7 +1096,7 @@ private:
class DrawColorOp : public DrawOp {
public:
DrawColorOp(int color, SkXfermode::Mode mode)
: DrawOp(0), mColor(color), mMode(mode) {};
: DrawOp(NULL), mColor(color), mMode(mode) {};
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
return renderer.drawColor(mColor, mMode);
@@ -1505,7 +1501,7 @@ private:
class DrawFunctorOp : public DrawOp {
public:
DrawFunctorOp(Functor* functor)
: DrawOp(0), mFunctor(functor) {}
: DrawOp(NULL), mFunctor(functor) {}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
renderer.startMark("GL functor");
@@ -1525,20 +1521,21 @@ private:
};
class DrawDisplayListOp : public DrawBoundedOp {
friend class DisplayList; // grant DisplayList access to info of child
public:
DrawDisplayListOp(DisplayList* displayList, int flags)
DrawDisplayListOp(DisplayList* displayList, int flags, const mat4& transformFromParent)
: DrawBoundedOp(0, 0, displayList->getWidth(), displayList->getHeight(), 0),
mDisplayList(displayList), mFlags(flags) {}
mDisplayList(displayList), mFlags(flags), mTransformFromParent(transformFromParent) {}
virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
bool useQuickReject) {
if (mDisplayList && mDisplayList->isRenderable()) {
if (mDisplayList && mDisplayList->isRenderable() && !mSkipInOrderDraw) {
mDisplayList->defer(deferStruct, level + 1);
}
}
virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
bool useQuickReject) {
if (mDisplayList && mDisplayList->isRenderable()) {
if (mDisplayList && mDisplayList->isRenderable() && !mSkipInOrderDraw) {
mDisplayList->replay(replayStruct, level + 1);
}
}
@@ -1559,13 +1556,58 @@ public:
private:
DisplayList* mDisplayList;
int mFlags;
const int mFlags;
///////////////////////////
// Properties below are used by DisplayList::computeOrderingImpl() and iterate()
///////////////////////////
/**
* Records transform vs parent, used for computing total transform without rerunning DL contents
*/
const mat4 mTransformFromParent;
/**
* Holds the transformation between the 3d root ViewGroup and this DisplayList drawing
* instance. Represents any translations / transformations done within the drawing of the 3d
* root ViewGroup's draw, before the draw of the View represented by this DisplayList draw
* instance.
*
* Note: doesn't include any transformation recorded within the DisplayList and its properties.
*/
mat4 mTransformFrom3dRoot;
bool mSkipInOrderDraw;
};
/**
* Not a canvas operation, used only by 3d / z ordering logic in DisplayList::iterate()
*/
class DrawShadowOp : public DrawOp {
public:
DrawShadowOp(const mat4& casterTransform, float casterAlpha, float width, float height)
: DrawOp(NULL), mCasterTransform(casterTransform), mCasterAlpha(casterAlpha),
mWidth(width), mHeight(height) {}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
return renderer.drawShadow(mCasterTransform, mCasterAlpha, mWidth, mHeight);
}
virtual void output(int level, uint32_t logFlags) const {
OP_LOG("DrawShadow of width %.2f, height %.2f", mWidth, mHeight);
}
virtual const char* name() { return "DrawShadow"; }
private:
const mat4 mCasterTransform;
const float mCasterAlpha;
const float mWidth;
const float mHeight;
};
class DrawLayerOp : public DrawOp {
public:
DrawLayerOp(Layer* layer, float x, float y)
: DrawOp(0), mLayer(layer), mX(x), mY(y) {}
: DrawOp(NULL), mLayer(layer), mX(x), mY(y) {}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
return renderer.drawLayer(mLayer, mX, mY);

View File

@@ -111,6 +111,7 @@ DisplayList* DisplayListRenderer::getDisplayList(DisplayList* displayList) {
} else {
displayList->initFromDisplayListRenderer(*this, true);
}
// TODO: should just avoid setting the DisplayList's DisplayListData
displayList->setRenderable(mHasDrawOps);
return displayList;
}
@@ -120,7 +121,8 @@ bool DisplayListRenderer::isDeferred() {
}
void DisplayListRenderer::setViewport(int width, int height) {
mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
// TODO: DisplayListRenderer shouldn't have a projection matrix, as it should never be used
mViewProjMatrix.loadOrtho(0, width, height, 0, -1, 1);
mWidth = width;
mHeight = height;
@@ -248,7 +250,10 @@ status_t DisplayListRenderer::drawDisplayList(DisplayList* displayList,
// resources cache, but we rely on the caller (UI toolkit) to
// do the right thing for now
addDrawOp(new (alloc()) DrawDisplayListOp(displayList, flags));
DrawDisplayListOp* op = new (alloc()) DrawDisplayListOp(displayList, flags, currentTransform());
addDrawOp(op);
mDisplayListData->children.push(op);
return DrawGlInfo::kStatusDone;
}

View File

@@ -328,6 +328,7 @@ private:
return patch;
}
// TODO: move these to DisplayListData
Vector<SkBitmap*> mBitmapResources;
Vector<SkBitmap*> mOwnedBitmapResources;
Vector<SkiaColorFilter*> mFilterResources;

View File

@@ -194,11 +194,9 @@ void Layer::defer() {
dirtyRect.set(0, 0, width, height);
}
if (deferredList) {
deferredList->reset(dirtyRect);
} else {
deferredList = new DeferredDisplayList(dirtyRect);
}
delete deferredList;
deferredList = new DeferredDisplayList(dirtyRect);
DeferStateStruct deferredState(*deferredList, *renderer,
DisplayList::kReplayFlag_ClipChildren);
@@ -206,6 +204,7 @@ void Layer::defer() {
renderer->setupFrameState(dirtyRect.left, dirtyRect.top,
dirtyRect.right, dirtyRect.bottom, !isBlend());
displayList->computeOrdering();
displayList->defer(deferredState, 0);
deferredUpdateScheduled = false;

View File

@@ -89,8 +89,9 @@ uint8_t Matrix4::getType() const {
float m01 = data[kSkewX];
float m10 = data[kSkewY];
float m11 = data[kScaleY];
float m32 = data[kTranslateZ];
if (m01 != 0.0f || m10 != 0.0f) {
if (m01 != 0.0f || m10 != 0.0f || m32 != 0.0f) {
mType |= kTypeAffine;
}
@@ -131,11 +132,13 @@ bool Matrix4::changesBounds() const {
}
bool Matrix4::isPureTranslate() const {
return getGeometryType() <= kTypeTranslate;
// NOTE: temporary hack to workaround ignoreTransform behavior with Z values
// TODO: separate this into isPure2dTranslate vs isPure3dTranslate
return getGeometryType() <= kTypeTranslate && (data[kTranslateZ] == 0.0f);
}
bool Matrix4::isSimple() const {
return getGeometryType() <= (kTypeScale | kTypeTranslate);
return getGeometryType() <= (kTypeScale | kTypeTranslate) && (data[kTranslateZ] == 0.0f);
}
bool Matrix4::isIdentity() const {
@@ -369,6 +372,84 @@ void Matrix4::loadMultiply(const Matrix4& u, const Matrix4& v) {
mType = kTypeUnknown;
}
// translated from android.opengl.Matrix#frustumM()
void Matrix4::loadFrustum(float left, float top, float right, float bottom, float near, float far) {
float r_width = 1.0f / (right - left);
float r_height = 1.0f / (top - bottom);
float r_depth = 1.0f / (near - far);
float x = 2.0f * (near * r_width);
float y = 2.0f * (near * r_height);
float A = (right + left) * r_width;
float B = (top + bottom) * r_height;
float C = (far + near) * r_depth;
float D = 2.0f * (far * near * r_depth);
memset(&data, 0, sizeof(data));
mType = kTypeUnknown;
data[kScaleX] = x;
data[kScaleY] = y;
data[8] = A;
data[9] = B;
data[kScaleZ] = C;
data[kTranslateZ] = D;
data[11] = -1.0f;
}
// translated from android.opengl.Matrix#setLookAtM()
void Matrix4::loadLookAt(float eyeX, float eyeY, float eyeZ,
float centerX, float centerY, float centerZ,
float upX, float upY, float upZ) {
float fx = centerX - eyeX;
float fy = centerY - eyeY;
float fz = centerZ - eyeZ;
// Normalize f
float rlf = 1.0f / sqrt(fx*fx + fy*fy + fz*fz);
fx *= rlf;
fy *= rlf;
fz *= rlf;
// compute s = f x up (x means "cross product")
float sx = fy * upZ - fz * upY;
float sy = fz * upX - fx * upZ;
float sz = fx * upY - fy * upX;
// and normalize s
float rls = 1.0f / sqrt(sx*sx + sy*sy + sz*sz);
sx *= rls;
sy *= rls;
sz *= rls;
// compute u = s x f
float ux = sy * fz - sz * fy;
float uy = sz * fx - sx * fz;
float uz = sx * fy - sy * fx;
mType = kTypeUnknown;
data[0] = sx;
data[1] = ux;
data[2] = -fx;
data[3] = 0.0f;
data[4] = sy;
data[5] = uy;
data[6] = -fy;
data[7] = 0.0f;
data[8] = sz;
data[9] = uz;
data[10] = -fz;
data[11] = 0.0f;
data[12] = 0.0f;
data[13] = 0.0f;
data[14] = 0.0f;
data[15] = 1.0f;
translate(-eyeX, -eyeY, -eyeZ);
}
void Matrix4::loadOrtho(float left, float right, float bottom, float top, float near, float far) {
loadIdentity();
@@ -382,6 +463,14 @@ void Matrix4::loadOrtho(float left, float right, float bottom, float top, float
mType = kTypeTranslate | kTypeScale | kTypeRectToRect;
}
void Matrix4::mapPoint3d(Vector3& vec) const {
//TODO: optimize simple case
Vector3 orig(vec);
vec.x = orig.x * data[kScaleX] + orig.y * data[kSkewX] + orig.z * data[8] + data[kTranslateX];
vec.y = orig.x * data[kSkewY] + orig.y * data[kScaleY] + orig.z * data[9] + data[kTranslateY];
vec.z = orig.x * data[2] + orig.y * data[6] + orig.z * data[kScaleZ] + data[kTranslateZ];
}
#define MUL_ADD_STORE(a, b, c) a = (a) * (b) + (c)
void Matrix4::mapPoint(float& x, float& y) const {

View File

@@ -121,6 +121,10 @@ public:
void loadRotate(float angle);
void loadRotate(float angle, float x, float y, float z);
void loadMultiply(const Matrix4& u, const Matrix4& v);
void loadFrustum(float left, float top, float right, float bottom, float near, float far);
void loadLookAt(float eyeX, float eyeY, float eyeZ,
float centerX, float centerY, float centerZ,
float upX, float upY, float upZ);
void loadOrtho(float left, float right, float bottom, float top, float near, float far);
@@ -134,17 +138,18 @@ public:
void multiply(float v);
void translate(float x, float y) {
void translate(float x, float y, float z = 0) {
if ((getType() & sGeometryMask) <= kTypeTranslate) {
data[kTranslateX] += x;
data[kTranslateY] += y;
data[kTranslateZ] += z;
} else {
// Doing a translation will only affect the translate bit of the type
// Save the type
uint8_t type = mType;
Matrix4 u;
u.loadTranslate(x, y, 0.0f);
u.loadTranslate(x, y, z);
multiply(u);
// Restore the type and fix the translate bit
@@ -190,8 +195,9 @@ public:
void copyTo(float* v) const;
void copyTo(SkMatrix& v) const;
void mapRect(Rect& r) const;
void mapPoint(float& x, float& y) const;
void mapPoint3d(Vector3& vec) const;
void mapPoint(float& x, float& y) const; // 2d only
void mapRect(Rect& r) const; // 2d only
float getTranslateX() const;
float getTranslateY() const;

View File

@@ -180,7 +180,21 @@ void OpenGLRenderer::setViewport(int width, int height) {
}
void OpenGLRenderer::initViewport(int width, int height) {
mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
float dist = std::max(width, height) * 1.5;
if (DEBUG_ENABLE_3D) {
// TODO: make view proj app configurable
Matrix4 projection;
projection.loadFrustum(-width / 2, -height / 2, width / 2, height / 2, dist, 0);
Matrix4 view;
view.loadLookAt(0, 0, dist,
0, 0, 0,
0, 1, 0);
mViewProjMatrix.loadMultiply(projection, view);
mViewProjMatrix.translate(-width/2, -height/2);
} else {
mViewProjMatrix.loadOrtho(0, width, height, 0, -1, 1);
}
mWidth = width;
mHeight = height;
@@ -753,7 +767,7 @@ bool OpenGLRenderer::restoreSnapshot() {
if (restoreOrtho) {
Rect& r = previous->viewport;
glViewport(r.left, r.top, r.right, r.bottom);
mOrthoMatrix.load(current->orthoMatrix);
mViewProjMatrix.load(current->orthoMatrix);
}
mSaveCount--;
@@ -984,7 +998,7 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) {
mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
mSnapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
mSnapshot->height = bounds.getHeight();
mSnapshot->orthoMatrix.load(mOrthoMatrix);
mSnapshot->orthoMatrix.load(mViewProjMatrix);
endTiling();
debugOverdraw(false, false);
@@ -1013,7 +1027,9 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) {
// Change the ortho projection
glViewport(0, 0, bounds.getWidth(), bounds.getHeight());
mOrthoMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f);
// TODO: determine best way to support 3d drawing within HW layers
mViewProjMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f);
return true;
}
@@ -1539,10 +1555,8 @@ void OpenGLRenderer::getMatrix(SkMatrix* matrix) {
}
void OpenGLRenderer::concatMatrix(SkMatrix* matrix) {
SkMatrix transform;
currentTransform().copyTo(transform);
transform.preConcat(*matrix);
currentTransform().load(transform);
mat4 transform(*matrix);
currentTransform().multiply(transform);
}
///////////////////////////////////////////////////////////////////////////////
@@ -1927,10 +1941,10 @@ void OpenGLRenderer::setupDrawModelView(ModelViewMode mode, bool offset,
bool dirty = right - left > 0.0f && bottom - top > 0.0f;
if (!ignoreTransform) {
mCaches.currentProgram->set(mOrthoMatrix, mModelView, currentTransform(), offset);
mCaches.currentProgram->set(mViewProjMatrix, mModelView, currentTransform(), offset);
if (dirty && mTrackDirtyRegions) dirtyLayer(left, top, right, bottom, currentTransform());
} else {
mCaches.currentProgram->set(mOrthoMatrix, mModelView, mat4::identity(), offset);
mCaches.currentProgram->set(mViewProjMatrix, mModelView, mat4::identity(), offset);
if (dirty && mTrackDirtyRegions) dirtyLayer(left, top, right, bottom);
}
}
@@ -2064,9 +2078,12 @@ void OpenGLRenderer::setupDrawIndexedVertices(GLvoid* vertices) {
status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty,
int32_t replayFlags) {
status_t status;
// All the usual checks and setup operations (quickReject, setupDraw, etc.)
// will be performed by the display list itself
if (displayList && displayList->isRenderable()) {
// compute 3d ordering
displayList->computeOrdering();
if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
status = startFrame();
ReplayStateStruct replayStruct(*this, dirty, replayFlags);
@@ -2082,7 +2099,7 @@ status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty,
flushLayers();
status = startFrame();
return status | deferredList.flush(*this, dirty);
return deferredList.flush(*this, dirty) | status;
}
return DrawGlInfo::kStatusDone;
@@ -3366,6 +3383,34 @@ status_t OpenGLRenderer::drawRects(const float* rects, int count, SkPaint* paint
return drawColorRects(rects, count, color, mode);
}
status_t OpenGLRenderer::drawShadow(const mat4& casterTransform, float casterAlpha,
float width, float height) {
if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
// For now, always and scissor
// TODO: use quickReject
mCaches.enableScissor();
SkPaint paint;
paint.setColor(0x3f000000);
paint.setAntiAlias(true);
VertexBuffer vertexBuffer;
{
//TODO: populate vertex buffer with better shadow geometry.
Vector3 pivot(width/2, height/2, 0.0f);
casterTransform.mapPoint3d(pivot);
float zScaleFactor = 0.5 + 0.0005f * pivot.z;
SkPath path;
path.addRect(pivot.x - width * zScaleFactor, pivot.y - height * zScaleFactor,
pivot.x + width * zScaleFactor, pivot.y + height * zScaleFactor);
PathTessellator::tessellatePath(path, &paint, mSnapshot->transform, vertexBuffer);
}
return drawVertexBuffer(vertexBuffer, &paint);
}
status_t OpenGLRenderer::drawColorRects(const float* rects, int count, int color,
SkXfermode::Mode mode, bool ignoreTransform, bool dirty, bool clip) {
if (count == 0) {

View File

@@ -265,6 +265,12 @@ public:
ANDROID_API void getMatrix(SkMatrix* matrix);
virtual void setMatrix(SkMatrix* matrix);
virtual void concatMatrix(SkMatrix* matrix);
virtual void concatMatrix(Matrix4& matrix) {
currentTransform().multiply(matrix);
}
void translateZ(float z) {
currentTransform().translate(0,0,z);
}
ANDROID_API const Rect& getClipBounds();
@@ -314,6 +320,9 @@ public:
DrawOpMode drawOpMode = kDrawOpMode_Immediate);
virtual status_t drawRects(const float* rects, int count, SkPaint* paint);
status_t drawShadow(const mat4& casterTransform, float casterAlpha,
float width, float height);
virtual void resetShader();
virtual void setupShader(SkiaShader* shader);
@@ -1069,8 +1078,8 @@ private:
// Dimensions of the drawing surface
int mWidth, mHeight;
// Matrix used for ortho projection in shaders
mat4 mOrthoMatrix;
// Matrix used for view/projection in shaders
mat4 mViewProjMatrix;
/**
* Model-view matrix used to position/size objects

View File

@@ -107,6 +107,21 @@ struct Vector2 {
}
}; // class Vector2
class Vector3 {
public:
float x;
float y;
float z;
Vector3() :
x(0.0f), y(0.0f), z(0.0f) {
}
Vector3(float px, float py, float pz) :
x(px), y(py), z(pz) {
}
};
///////////////////////////////////////////////////////////////////////////////
// Types
///////////////////////////////////////////////////////////////////////////////