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/Snapshot.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'libs/hwui/Snapshot.cpp') diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp index 9e7faee69fba..beb2e1d0481c 100644 --- a/libs/hwui/Snapshot.cpp +++ b/libs/hwui/Snapshot.cpp @@ -36,6 +36,7 @@ Snapshot::Snapshot() , empty(false) , alpha(1.0f) , roundRectClipState(nullptr) + , projectionPathMask(nullptr) , mClipArea(&mClipAreaRoot) { transform = &mTransformRoot; region = nullptr; @@ -54,6 +55,7 @@ Snapshot::Snapshot(const sp& s, int saveFlags) , empty(false) , alpha(s->alpha) , roundRectClipState(s->roundRectClipState) + , projectionPathMask(s->projectionPathMask) , mClipArea(nullptr) , mViewportData(s->mViewportData) , mRelativeLightCenter(s->mRelativeLightCenter) { @@ -141,6 +143,34 @@ void Snapshot::resetTransform(float x, float y, float z) { transform->loadTranslate(x, y, z); } +void Snapshot::buildScreenSpaceTransform(Matrix4* outTransform) const { + // build (reverse ordered) list of the stack of snapshots, terminated with a NULL + Vector snapshotList; + snapshotList.push(nullptr); + const Snapshot* current = this; + do { + snapshotList.push(current); + current = current->previous.get(); + } while (current); + + // traverse the list, adding in each transform that contributes to the total transform + outTransform->loadIdentity(); + for (size_t i = snapshotList.size() - 1; i > 0; i--) { + // iterate down the stack + const Snapshot* current = snapshotList[i]; + const Snapshot* next = snapshotList[i - 1]; + if (current->flags & kFlagIsFboLayer) { + // if we've hit a layer, translate by the layer's draw offset + outTransform->translate(current->layer->layer.left, current->layer->layer.top); + } + if (!next || (next->flags & kFlagIsFboLayer)) { + // if this snapshot is last, or if this snapshot is last before an + // FBO layer (which reset the transform), apply it + outTransform->multiply(*(current->transform)); + } + } +} + /////////////////////////////////////////////////////////////////////////////// // Clipping round rect /////////////////////////////////////////////////////////////////////////////// @@ -191,6 +221,18 @@ void Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& boun roundRectClipState = state; } +void Snapshot::setProjectionPathMask(LinearAllocator& allocator, const SkPath* path) { + if (path) { + ProjectionPathMask* mask = new (allocator) ProjectionPathMask; + mask->projectionMask = path; + buildScreenSpaceTransform(&(mask->projectionMaskTransform)); + + projectionPathMask = mask; + } else { + projectionPathMask = nullptr; + } +} + /////////////////////////////////////////////////////////////////////////////// // Queries /////////////////////////////////////////////////////////////////////////////// -- cgit v1.2.3-59-g8ed1b