From fca52b7583d1e5f5ff8ed06554875d2a30ef56fa Mon Sep 17 00:00:00 2001 From: Chris Craik Date: Tue, 28 Apr 2015 11:45:59 -0700 Subject: Use path intersection instead of saveLayer+mesh to mask projected ripples bug:14297149 SaveLayer's performance cost is high, and proportional to the surface being projected onto. Since ripples (even unbounded ones) are now always projected to the arbitrary background content behind them, this cost is especially important to avoid. This removes the last semi-secret, saveLayer from the projected ripple implementation. Also fixes the HW test app to correctly demonstrate this projection masking behavior. Additionaly, alters PathTessellator to gracefully handle counter-clockwise paths, and simplifies the work done by ShadowTessellator to ensure all of its paths are counterclockwise. Change-Id: Ibe9e12812bd10a774e20b1d444a140c368cbba8c --- libs/hwui/OpenGLRenderer.cpp | 46 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 8 deletions(-) (limited to 'libs/hwui/OpenGLRenderer.cpp') diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 54bcd7e43d1d..d87a3e63ceac 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -40,6 +40,7 @@ #include #include +#include #include #include @@ -1193,8 +1194,9 @@ bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDef state.mMatrix.load(*currentMatrix); state.mAlpha = currentSnapshot()->alpha; - // always store/restore, since it's just a pointer + // always store/restore, since these are just pointers state.mRoundRectClipState = currentSnapshot()->roundRectClipState; + state.mProjectionPathMask = currentSnapshot()->projectionPathMask; return false; } @@ -1202,6 +1204,7 @@ void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool setMatrix(state.mMatrix); writableSnapshot()->alpha = state.mAlpha; writableSnapshot()->roundRectClipState = state.mRoundRectClipState; + writableSnapshot()->projectionPathMask = state.mProjectionPathMask; if (state.mClipValid && !skipClipRestore) { writableSnapshot()->setClip(state.mClip.left, state.mClip.top, @@ -1755,6 +1758,7 @@ void OpenGLRenderer::drawVertexBuffer(float translateX, float translateY, void OpenGLRenderer::drawConvexPath(const SkPath& path, const SkPaint* paint) { VertexBuffer vertexBuffer; // TODO: try clipping large paths to viewport + PathTessellator::tessellatePath(path, paint, *currentTransform(), vertexBuffer); drawVertexBuffer(vertexBuffer, paint); } @@ -1861,19 +1865,41 @@ void OpenGLRenderer::drawCircle(float x, float y, float radius, const SkPaint* p || PaintUtils::paintWillNotDraw(*p)) { return; } + if (p->getPathEffect() != nullptr) { mCaches.textureState().activateTexture(0); PathTexture* texture = mCaches.pathCache.getCircle(radius, p); drawShape(x - radius, y - radius, texture, p); + return; + } + + SkPath path; + if (p->getStyle() == SkPaint::kStrokeAndFill_Style) { + path.addCircle(x, y, radius + p->getStrokeWidth() / 2); } else { - SkPath path; - if (p->getStyle() == SkPaint::kStrokeAndFill_Style) { - path.addCircle(x, y, radius + p->getStrokeWidth() / 2); - } else { - path.addCircle(x, y, radius); - } - drawConvexPath(path, p); + path.addCircle(x, y, radius); + } + + if (CC_UNLIKELY(currentSnapshot()->projectionPathMask != nullptr)) { + // mask ripples with projection mask + SkPath maskPath = *(currentSnapshot()->projectionPathMask->projectionMask); + + Matrix4 screenSpaceTransform; + currentSnapshot()->buildScreenSpaceTransform(&screenSpaceTransform); + + Matrix4 totalTransform; + totalTransform.loadInverse(screenSpaceTransform); + totalTransform.multiply(currentSnapshot()->projectionPathMask->projectionMaskTransform); + + SkMatrix skTotalTransform; + totalTransform.copyTo(skTotalTransform); + maskPath.transform(skTotalTransform); + + // Mask the ripple path by the projection mask, now that it's + // in local space. Note that this can create CCW paths. + Op(path, maskPath, kIntersect_PathOp, &path); } + drawConvexPath(path, p); } void OpenGLRenderer::drawOval(float left, float top, float right, float bottom, @@ -2146,6 +2172,10 @@ void OpenGLRenderer::setClippingRoundRect(LinearAllocator& allocator, mState.setClippingRoundRect(allocator, rect, radius, highPriority); } +void OpenGLRenderer::setProjectionPathMask(LinearAllocator& allocator, const SkPath* path) { + mState.setProjectionPathMask(allocator, path); +} + void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float x, float y, const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds, DrawOpMode drawOpMode) { -- cgit v1.2.3-59-g8ed1b