1ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy/*
2ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy * Copyright (C) 2012 The Android Open Source Project
3ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy *
4ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy * Licensed under the Apache License, Version 2.0 (the "License");
5ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy * you may not use this file except in compliance with the License.
6ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy * You may obtain a copy of the License at
7ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy *
8ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy *      http://www.apache.org/licenses/LICENSE-2.0
9ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy *
10ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy * Unless required by applicable law or agreed to in writing, software
11ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy * distributed under the License is distributed on an "AS IS" BASIS,
12ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy * See the License for the specific language governing permissions and
14ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy * limitations under the License.
15ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy */
16ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy
17ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy#include "Snapshot.h"
18ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy
19dccca44ffda4836b56a21da95a046c9708ffd49csergeyv#include "hwui/Canvas.h"
20ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy
21ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guynamespace android {
22ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guynamespace uirenderer {
23ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy
24ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy///////////////////////////////////////////////////////////////////////////////
25ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy// Constructors
26ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy///////////////////////////////////////////////////////////////////////////////
27ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy
28e4aa95e3627226bcb0d8cc3e42dca6e4df8f421cChris CraikSnapshot::Snapshot()
29e4aa95e3627226bcb0d8cc3e42dca6e4df8f421cChris Craik        : flags(0)
30d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik        , previous(nullptr)
31d41c4d8c732095ae99c955b6b82f7306633004b1Chris Craik        , layer(nullptr)
32e4aa95e3627226bcb0d8cc3e42dca6e4df8f421cChris Craik        , fbo(0)
33deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik        , alpha(1.0f)
34487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        , roundRectClipState(nullptr)
35fca52b7583d1e5f5ff8ed06554875d2a30ef56faChris Craik        , projectionPathMask(nullptr)
36487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        , mClipArea(&mClipAreaRoot) {
37ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy    transform = &mTransformRoot;
38de89c2fd708d9d7a7e7990e2d6da77c8481a0217Keith Mok    mRelativeLightCenter.x = mRelativeLightCenter.y = mRelativeLightCenter.z = 0;
39ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy}
40ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy
41ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy/**
42ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy * Copies the specified snapshot/ The specified snapshot is stored as
43ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy * the previous snapshot.
44ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy */
45d9ee550888011a64fa3f35e666360ec8278597d8John ReckSnapshot::Snapshot(Snapshot* s, int saveFlags)
46e4aa95e3627226bcb0d8cc3e42dca6e4df8f421cChris Craik        : flags(0)
47e4aa95e3627226bcb0d8cc3e42dca6e4df8f421cChris Craik        , previous(s)
48e4aa95e3627226bcb0d8cc3e42dca6e4df8f421cChris Craik        , layer(s->layer)
49e4aa95e3627226bcb0d8cc3e42dca6e4df8f421cChris Craik        , fbo(s->fbo)
50a64a2bef1048db5a742843f1e3bea9e80d0defc5Chris Craik        , alpha(s->alpha)
51deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik        , roundRectClipState(s->roundRectClipState)
52fca52b7583d1e5f5ff8ed06554875d2a30ef56faChris Craik        , projectionPathMask(s->projectionPathMask)
53487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        , mClipArea(nullptr)
5469e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik        , mViewportData(s->mViewportData)
5569e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik        , mRelativeLightCenter(s->mRelativeLightCenter) {
56eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita    if (saveFlags & SaveFlags::Matrix) {
577c85c54499994c687a833644f7f213e747fadb98Chris Craik        mTransformRoot = *s->transform;
58ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy        transform = &mTransformRoot;
59ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy    } else {
60ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy        transform = s->transform;
61ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy    }
62ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy
63eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita    if (saveFlags & SaveFlags::Clip) {
64487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        mClipAreaRoot = s->getClipArea();
65487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        mClipArea = &mClipAreaRoot;
66ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy    } else {
67487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        mClipArea = s->mClipArea;
68ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy    }
69ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy}
70ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy
71ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy///////////////////////////////////////////////////////////////////////////////
72ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy// Clipping
73ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy///////////////////////////////////////////////////////////////////////////////
74ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy
756e49c9f007c879f05b035c40c0ba543c00f9d0d0Mike Reedvoid Snapshot::clip(const Rect& localClip, SkClipOp op) {
76487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    flags |= Snapshot::kFlagClipSet;
776e49c9f007c879f05b035c40c0ba543c00f9d0d0Mike Reed    mClipArea->clipRectWithTransform(localClip, transform, static_cast<SkRegion::Op>(op));
78ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy}
79ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy
806e49c9f007c879f05b035c40c0ba543c00f9d0d0Mike Reedvoid Snapshot::clipPath(const SkPath& path, SkClipOp op) {
81487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    flags |= Snapshot::kFlagClipSet;
826e49c9f007c879f05b035c40c0ba543c00f9d0d0Mike Reed    mClipArea->clipPathWithTransform(path, transform, static_cast<SkRegion::Op>(op));
83ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy}
84ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy
85ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guyvoid Snapshot::setClip(float left, float top, float right, float bottom) {
86ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy    flags |= Snapshot::kFlagClipSet;
874d3e704b04c6abd7995df640d12662b0271f6c7bChris Craik    mClipArea->setClip(left, top, right, bottom);
88ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy}
89ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy
90a3dc55f83ab583e0a66b893c71b849afa046770aRomain Guybool Snapshot::hasPerspectiveTransform() const {
91a3dc55f83ab583e0a66b893c71b849afa046770aRomain Guy    return transform->isPerspective();
92a3dc55f83ab583e0a66b893c71b849afa046770aRomain Guy}
93a3dc55f83ab583e0a66b893c71b849afa046770aRomain Guy
94ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guyconst Rect& Snapshot::getLocalClip() {
95ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy    mat4 inverse;
96ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy    inverse.loadInverse(*transform);
97ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy
98487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mLocalClip.set(mClipArea->getClipRect());
99ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy    inverse.mapRect(mLocalClip);
100ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy
101ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy    return mLocalClip;
102ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy}
103ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy
104ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guyvoid Snapshot::resetClip(float left, float top, float right, float bottom) {
1053bbacf27c0be1bae4e4483577fc89ae3113abe5dRomain Guy    // TODO: This is incorrect, when we start rendering into a new layer,
1063bbacf27c0be1bae4e4483577fc89ae3113abe5dRomain Guy    // we may have to modify the previous snapshot's clip rect and clip
1073bbacf27c0be1bae4e4483577fc89ae3113abe5dRomain Guy    // region if the previous restore() call did not restore the clip
108487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    mClipArea = &mClipAreaRoot;
109967e2bf3ac8943a8e8a374bf86021915445cda67Romain Guy    setClip(left, top, right, bottom);
110ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy}
111ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy
112ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy///////////////////////////////////////////////////////////////////////////////
113af4d04cab6d48ae0d6a5e79bd30f679af87abaadChris Craik// Clipping round rect
114deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik///////////////////////////////////////////////////////////////////////////////
115deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik
116e83cbd451868a734bfac07ccd680d5617080b579Chris Craikvoid Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds,
117e83cbd451868a734bfac07ccd680d5617080b579Chris Craik        float radius, bool highPriority) {
118af4d04cab6d48ae0d6a5e79bd30f679af87abaadChris Craik    if (bounds.isEmpty()) {
119487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        mClipArea->setEmpty();
120af4d04cab6d48ae0d6a5e79bd30f679af87abaadChris Craik        return;
121af4d04cab6d48ae0d6a5e79bd30f679af87abaadChris Craik    }
122deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik
123e83cbd451868a734bfac07ccd680d5617080b579Chris Craik    if (roundRectClipState && roundRectClipState->highPriority) {
124e83cbd451868a734bfac07ccd680d5617080b579Chris Craik        // ignore, don't replace, already have a high priority clip
125e83cbd451868a734bfac07ccd680d5617080b579Chris Craik        return;
126e83cbd451868a734bfac07ccd680d5617080b579Chris Craik    }
127e83cbd451868a734bfac07ccd680d5617080b579Chris Craik
128deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik    RoundRectClipState* state = new (allocator) RoundRectClipState;
129deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik
130e83cbd451868a734bfac07ccd680d5617080b579Chris Craik    state->highPriority = highPriority;
131e83cbd451868a734bfac07ccd680d5617080b579Chris Craik
132deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik    // store the inverse drawing matrix
1337c85c54499994c687a833644f7f213e747fadb98Chris Craik    Matrix4 roundRectDrawingMatrix = getOrthoMatrix();
134af4d04cab6d48ae0d6a5e79bd30f679af87abaadChris Craik    roundRectDrawingMatrix.multiply(*transform);
135af4d04cab6d48ae0d6a5e79bd30f679af87abaadChris Craik    state->matrix.loadInverse(roundRectDrawingMatrix);
136deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik
137deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik    // compute area under rounded corners - only draws overlapping these rects need to be clipped
138deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik    for (int i = 0 ; i < 4; i++) {
139deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik        state->dangerRects[i] = bounds;
140deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik    }
141deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik    state->dangerRects[0].bottom = state->dangerRects[1].bottom = bounds.top + radius;
142deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik    state->dangerRects[0].right = state->dangerRects[2].right = bounds.left + radius;
143deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik    state->dangerRects[1].left = state->dangerRects[3].left = bounds.right - radius;
144deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik    state->dangerRects[2].top = state->dangerRects[3].top = bounds.bottom - radius;
145deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik    for (int i = 0; i < 4; i++) {
146deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik        transform->mapRect(state->dangerRects[i]);
147deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik
148deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik        // round danger rects out as though they are AA geometry (since they essentially are)
149deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik        state->dangerRects[i].snapGeometryToPixelBoundaries(true);
150deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik    }
151deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik
152deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik    // store RR area
153af4d04cab6d48ae0d6a5e79bd30f679af87abaadChris Craik    state->innerRect = bounds;
154af4d04cab6d48ae0d6a5e79bd30f679af87abaadChris Craik    state->innerRect.inset(radius);
155af4d04cab6d48ae0d6a5e79bd30f679af87abaadChris Craik    state->radius = radius;
156deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik
157deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik    // store as immutable so, for this frame, pointer uniquely identifies this bundle of shader info
158deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik    roundRectClipState = state;
159deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik}
160deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik
1615e00c7ce063116c11315639f0035aca8ad73e8ccChris Craikvoid Snapshot::setProjectionPathMask(const SkPath* path) {
162678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    projectionPathMask = path;
163fca52b7583d1e5f5ff8ed06554875d2a30ef56faChris Craik}
164fca52b7583d1e5f5ff8ed06554875d2a30ef56faChris Craik
16504d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craikstatic Snapshot* getClipRoot(Snapshot* target) {
16604d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    while (target->previous && target->previous->previous) {
16704d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik        target = target->previous;
16804d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    }
16904d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    return target;
17004d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik}
17104d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik
17204d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craikconst ClipBase* Snapshot::serializeIntersectedClip(LinearAllocator& allocator,
17304d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik        const ClipBase* recordedClip, const Matrix4& recordedClipTransform) {
17404d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    auto target = this;
17504d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    if (CC_UNLIKELY(recordedClip && recordedClip->intersectWithRoot)) {
17604d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik        // Clip must be intersected with root, instead of current clip.
17704d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik        target = getClipRoot(this);
17804d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    }
17904d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik
18004d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    return target->mClipArea->serializeIntersectedClip(allocator,
18104d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik            recordedClip, recordedClipTransform);
18204d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik}
18304d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik
18404d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craikvoid Snapshot::applyClip(const ClipBase* recordedClip, const Matrix4& transform) {
18504d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    if (CC_UNLIKELY(recordedClip && recordedClip->intersectWithRoot)) {
18604d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik        // current clip is being replaced, but must intersect with clip root
18704d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik        *mClipArea = *(getClipRoot(this)->mClipArea);
18804d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    }
18904d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    mClipArea->applyClip(recordedClip, transform);
19004d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik}
19104d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik
192deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik///////////////////////////////////////////////////////////////////////////////
193ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy// Queries
194ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy///////////////////////////////////////////////////////////////////////////////
195ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy
1965f803623559aab395a29d575c37c4e39c23a4b4eChris Craikvoid Snapshot::dump() const {
1975e00c7ce063116c11315639f0035aca8ad73e8ccChris Craik    ALOGD("Snapshot %p, flags %x, prev %p, height %d, hasComplexClip %d",
1985e00c7ce063116c11315639f0035aca8ad73e8ccChris Craik            this, flags, previous, getViewportHeight(), !mClipArea->isSimple());
199487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    const Rect& clipRect(mClipArea->getClipRect());
200e9c01a40a2f0f0da195dfbb2909aaee5c005d1c6Chris Craik    ALOGD("  ClipRect %.1f %.1f %.1f %.1f, clip simple %d",
201e9c01a40a2f0f0da195dfbb2909aaee5c005d1c6Chris Craik            clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, mClipArea->isSimple());
202e9c01a40a2f0f0da195dfbb2909aaee5c005d1c6Chris Craik
2035f803623559aab395a29d575c37c4e39c23a4b4eChris Craik    ALOGD("  Transform (at %p):", transform);
2045f803623559aab395a29d575c37c4e39c23a4b4eChris Craik    transform->dump();
2055f803623559aab395a29d575c37c4e39c23a4b4eChris Craik}
2065f803623559aab395a29d575c37c4e39c23a4b4eChris Craik
207ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy}; // namespace uirenderer
208ada4d53d50dc869b8278573ad640dc44118d3bcfRomain Guy}; // namespace android
209