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