Snapshot.cpp revision de89c2fd708d9d7a7e7990e2d6da77c8481a0217
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "OpenGLRenderer"
18
19#include "Snapshot.h"
20
21#include <SkCanvas.h>
22
23namespace android {
24namespace uirenderer {
25
26///////////////////////////////////////////////////////////////////////////////
27// Constructors
28///////////////////////////////////////////////////////////////////////////////
29
30Snapshot::Snapshot()
31        : flags(0)
32        , previous(nullptr)
33        , layer(nullptr)
34        , fbo(0)
35        , invisible(false)
36        , empty(false)
37        , alpha(1.0f)
38        , roundRectClipState(nullptr)
39        , projectionPathMask(nullptr)
40        , mClipArea(&mClipAreaRoot) {
41    transform = &mTransformRoot;
42    region = nullptr;
43    mRelativeLightCenter.x = mRelativeLightCenter.y = mRelativeLightCenter.z = 0;
44}
45
46/**
47 * Copies the specified snapshot/ The specified snapshot is stored as
48 * the previous snapshot.
49 */
50Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags)
51        : flags(0)
52        , previous(s)
53        , layer(s->layer)
54        , fbo(s->fbo)
55        , invisible(s->invisible)
56        , empty(false)
57        , alpha(s->alpha)
58        , roundRectClipState(s->roundRectClipState)
59        , projectionPathMask(s->projectionPathMask)
60        , mClipArea(nullptr)
61        , mViewportData(s->mViewportData)
62        , mRelativeLightCenter(s->mRelativeLightCenter) {
63    if (saveFlags & SkCanvas::kMatrix_SaveFlag) {
64        mTransformRoot.load(*s->transform);
65        transform = &mTransformRoot;
66    } else {
67        transform = s->transform;
68    }
69
70    if (saveFlags & SkCanvas::kClip_SaveFlag) {
71        mClipAreaRoot = s->getClipArea();
72        mClipArea = &mClipAreaRoot;
73    } else {
74        mClipArea = s->mClipArea;
75    }
76
77    if (s->flags & Snapshot::kFlagFboTarget) {
78        flags |= Snapshot::kFlagFboTarget;
79        region = s->region;
80    } else {
81        region = nullptr;
82    }
83}
84
85///////////////////////////////////////////////////////////////////////////////
86// Clipping
87///////////////////////////////////////////////////////////////////////////////
88
89bool Snapshot::clipRegionTransformed(const SkRegion& region, SkRegion::Op op) {
90    flags |= Snapshot::kFlagClipSet;
91    return mClipArea->clipRegion(region, op);
92}
93
94bool Snapshot::clip(float left, float top, float right, float bottom, SkRegion::Op op) {
95    flags |= Snapshot::kFlagClipSet;
96    return mClipArea->clipRectWithTransform(left, top, right, bottom, transform, op);
97}
98
99bool Snapshot::clipPath(const SkPath& path, SkRegion::Op op) {
100    flags |= Snapshot::kFlagClipSet;
101    return mClipArea->clipPathWithTransform(path, transform, op);
102}
103
104void Snapshot::setClip(float left, float top, float right, float bottom) {
105    mClipArea->setClip(left, top, right, bottom);
106    flags |= Snapshot::kFlagClipSet;
107}
108
109bool Snapshot::hasPerspectiveTransform() const {
110    return transform->isPerspective();
111}
112
113const Rect& Snapshot::getLocalClip() {
114    mat4 inverse;
115    inverse.loadInverse(*transform);
116
117    mLocalClip.set(mClipArea->getClipRect());
118    inverse.mapRect(mLocalClip);
119
120    return mLocalClip;
121}
122
123void Snapshot::resetClip(float left, float top, float right, float bottom) {
124    // TODO: This is incorrect, when we start rendering into a new layer,
125    // we may have to modify the previous snapshot's clip rect and clip
126    // region if the previous restore() call did not restore the clip
127    mClipArea = &mClipAreaRoot;
128    setClip(left, top, right, bottom);
129}
130
131///////////////////////////////////////////////////////////////////////////////
132// Transforms
133///////////////////////////////////////////////////////////////////////////////
134
135void Snapshot::resetTransform(float x, float y, float z) {
136    // before resetting, map current light pos with inverse of current transform
137    Vector3 center = mRelativeLightCenter;
138    mat4 inverse;
139    inverse.loadInverse(*transform);
140    inverse.mapPoint3d(center);
141    mRelativeLightCenter = center;
142
143    transform = &mTransformRoot;
144    transform->loadTranslate(x, y, z);
145}
146
147void Snapshot::buildScreenSpaceTransform(Matrix4* outTransform) const {
148    // build (reverse ordered) list of the stack of snapshots, terminated with a NULL
149    Vector<const Snapshot*> snapshotList;
150    snapshotList.push(nullptr);
151    const Snapshot* current = this;
152    do {
153        snapshotList.push(current);
154        current = current->previous.get();
155    } while (current);
156
157    // traverse the list, adding in each transform that contributes to the total transform
158    outTransform->loadIdentity();
159    for (size_t i = snapshotList.size() - 1; i > 0; i--) {
160        // iterate down the stack
161        const Snapshot* current = snapshotList[i];
162        const Snapshot* next = snapshotList[i - 1];
163        if (current->flags & kFlagIsFboLayer) {
164            // if we've hit a layer, translate by the layer's draw offset
165            outTransform->translate(current->layer->layer.left, current->layer->layer.top);
166        }
167        if (!next || (next->flags & kFlagIsFboLayer)) {
168            // if this snapshot is last, or if this snapshot is last before an
169            // FBO layer (which reset the transform), apply it
170            outTransform->multiply(*(current->transform));
171        }
172    }
173}
174
175///////////////////////////////////////////////////////////////////////////////
176// Clipping round rect
177///////////////////////////////////////////////////////////////////////////////
178
179void Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds,
180        float radius, bool highPriority) {
181    if (bounds.isEmpty()) {
182        mClipArea->setEmpty();
183        return;
184    }
185
186    if (roundRectClipState && roundRectClipState->highPriority) {
187        // ignore, don't replace, already have a high priority clip
188        return;
189    }
190
191    RoundRectClipState* state = new (allocator) RoundRectClipState;
192
193    state->highPriority = highPriority;
194
195    // store the inverse drawing matrix
196    Matrix4 roundRectDrawingMatrix;
197    roundRectDrawingMatrix.load(getOrthoMatrix());
198    roundRectDrawingMatrix.multiply(*transform);
199    state->matrix.loadInverse(roundRectDrawingMatrix);
200
201    // compute area under rounded corners - only draws overlapping these rects need to be clipped
202    for (int i = 0 ; i < 4; i++) {
203        state->dangerRects[i] = bounds;
204    }
205    state->dangerRects[0].bottom = state->dangerRects[1].bottom = bounds.top + radius;
206    state->dangerRects[0].right = state->dangerRects[2].right = bounds.left + radius;
207    state->dangerRects[1].left = state->dangerRects[3].left = bounds.right - radius;
208    state->dangerRects[2].top = state->dangerRects[3].top = bounds.bottom - radius;
209    for (int i = 0; i < 4; i++) {
210        transform->mapRect(state->dangerRects[i]);
211
212        // round danger rects out as though they are AA geometry (since they essentially are)
213        state->dangerRects[i].snapGeometryToPixelBoundaries(true);
214    }
215
216    // store RR area
217    state->innerRect = bounds;
218    state->innerRect.inset(radius);
219    state->radius = radius;
220
221    // store as immutable so, for this frame, pointer uniquely identifies this bundle of shader info
222    roundRectClipState = state;
223}
224
225void Snapshot::setProjectionPathMask(LinearAllocator& allocator, const SkPath* path) {
226    if (path) {
227        ProjectionPathMask* mask = new (allocator) ProjectionPathMask;
228        mask->projectionMask = path;
229        buildScreenSpaceTransform(&(mask->projectionMaskTransform));
230
231        projectionPathMask = mask;
232    } else {
233        projectionPathMask = nullptr;
234    }
235}
236
237///////////////////////////////////////////////////////////////////////////////
238// Queries
239///////////////////////////////////////////////////////////////////////////////
240
241bool Snapshot::isIgnored() const {
242    return invisible || empty;
243}
244
245void Snapshot::dump() const {
246    ALOGD("Snapshot %p, flags %x, prev %p, height %d, ignored %d, hasComplexClip %d",
247            this, flags, previous.get(), getViewportHeight(), isIgnored(), !mClipArea->isSimple());
248    const Rect& clipRect(mClipArea->getClipRect());
249    ALOGD("  ClipRect %.1f %.1f %.1f %.1f, clip simple %d",
250            clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, mClipArea->isSimple());
251
252    ALOGD("  Transform (at %p):", transform);
253    transform->dump();
254}
255
256}; // namespace uirenderer
257}; // namespace android
258