• 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(NULL)
33         , layer(NULL)
34         , fbo(0)
35         , invisible(false)
36         , empty(false)
37         , alpha(1.0f)
38         , roundRectClipState(NULL) {
39     transform = &mTransformRoot;
40     clipRect = &mClipRectRoot;
41     region = NULL;
42     clipRegion = &mClipRegionRoot;
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         , mViewportData(s->mViewportData)
59         , mRelativeLightCenter(s->mRelativeLightCenter) {
60     if (saveFlags & SkCanvas::kMatrix_SaveFlag) {
61         mTransformRoot.load(*s->transform);
62         transform = &mTransformRoot;
63     } else {
64         transform = s->transform;
65     }
66 
67     if (saveFlags & SkCanvas::kClip_SaveFlag) {
68         mClipRectRoot.set(*s->clipRect);
69         clipRect = &mClipRectRoot;
70         if (!s->clipRegion->isEmpty()) {
71             mClipRegionRoot.op(*s->clipRegion, SkRegion::kUnion_Op);
72         }
73         clipRegion = &mClipRegionRoot;
74     } else {
75         clipRect = s->clipRect;
76         clipRegion = s->clipRegion;
77     }
78 
79     if (s->flags & Snapshot::kFlagFboTarget) {
80         flags |= Snapshot::kFlagFboTarget;
81         region = s->region;
82     } else {
83         region = NULL;
84     }
85 }
86 
87 ///////////////////////////////////////////////////////////////////////////////
88 // Clipping
89 ///////////////////////////////////////////////////////////////////////////////
90 
ensureClipRegion()91 void Snapshot::ensureClipRegion() {
92     if (clipRegion->isEmpty()) {
93         clipRegion->setRect(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
94     }
95 }
96 
copyClipRectFromRegion()97 void Snapshot::copyClipRectFromRegion() {
98     if (!clipRegion->isEmpty()) {
99         const SkIRect& bounds = clipRegion->getBounds();
100         clipRect->set(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
101 
102         if (clipRegion->isRect()) {
103             clipRegion->setEmpty();
104         }
105     } else {
106         clipRect->setEmpty();
107     }
108 }
109 
clipRegionOp(float left,float top,float right,float bottom,SkRegion::Op op)110 bool Snapshot::clipRegionOp(float left, float top, float right, float bottom, SkRegion::Op op) {
111     SkIRect tmp;
112     tmp.set(left, top, right, bottom);
113     clipRegion->op(tmp, op);
114     copyClipRectFromRegion();
115     return true;
116 }
117 
clipRegionTransformed(const SkRegion & region,SkRegion::Op op)118 bool Snapshot::clipRegionTransformed(const SkRegion& region, SkRegion::Op op) {
119     ensureClipRegion();
120     clipRegion->op(region, op);
121     copyClipRectFromRegion();
122     flags |= Snapshot::kFlagClipSet;
123     return true;
124 }
125 
clip(float left,float top,float right,float bottom,SkRegion::Op op)126 bool Snapshot::clip(float left, float top, float right, float bottom, SkRegion::Op op) {
127     Rect r(left, top, right, bottom);
128     transform->mapRect(r);
129     return clipTransformed(r, op);
130 }
131 
clipTransformed(const Rect & r,SkRegion::Op op)132 bool Snapshot::clipTransformed(const Rect& r, SkRegion::Op op) {
133     bool clipped = false;
134 
135     switch (op) {
136         case SkRegion::kIntersect_Op: {
137             if (CC_UNLIKELY(!clipRegion->isEmpty())) {
138                 ensureClipRegion();
139                 clipped = clipRegionOp(r.left, r.top, r.right, r.bottom, SkRegion::kIntersect_Op);
140             } else {
141                 clipped = clipRect->intersect(r);
142                 if (!clipped) {
143                     clipRect->setEmpty();
144                     clipped = true;
145                 }
146             }
147             break;
148         }
149         case SkRegion::kReplace_Op: {
150             setClip(r.left, r.top, r.right, r.bottom);
151             clipped = true;
152             break;
153         }
154         default: {
155             ensureClipRegion();
156             clipped = clipRegionOp(r.left, r.top, r.right, r.bottom, op);
157             break;
158         }
159     }
160 
161     if (clipped) {
162         flags |= Snapshot::kFlagClipSet;
163     }
164 
165     return clipped;
166 }
167 
setClip(float left,float top,float right,float bottom)168 void Snapshot::setClip(float left, float top, float right, float bottom) {
169     clipRect->set(left, top, right, bottom);
170     if (!clipRegion->isEmpty()) {
171         clipRegion->setEmpty();
172     }
173     flags |= Snapshot::kFlagClipSet;
174 }
175 
hasPerspectiveTransform() const176 bool Snapshot::hasPerspectiveTransform() const {
177     return transform->isPerspective();
178 }
179 
getLocalClip()180 const Rect& Snapshot::getLocalClip() {
181     mat4 inverse;
182     inverse.loadInverse(*transform);
183 
184     mLocalClip.set(*clipRect);
185     inverse.mapRect(mLocalClip);
186 
187     return mLocalClip;
188 }
189 
resetClip(float left,float top,float right,float bottom)190 void Snapshot::resetClip(float left, float top, float right, float bottom) {
191     // TODO: This is incorrect, when we start rendering into a new layer,
192     // we may have to modify the previous snapshot's clip rect and clip
193     // region if the previous restore() call did not restore the clip
194     clipRect = &mClipRectRoot;
195     clipRegion = &mClipRegionRoot;
196     setClip(left, top, right, bottom);
197 }
198 
199 ///////////////////////////////////////////////////////////////////////////////
200 // Transforms
201 ///////////////////////////////////////////////////////////////////////////////
202 
resetTransform(float x,float y,float z)203 void Snapshot::resetTransform(float x, float y, float z) {
204     // before resetting, map current light pos with inverse of current transform
205     Vector3 center = mRelativeLightCenter;
206     mat4 inverse;
207     inverse.loadInverse(*transform);
208     inverse.mapPoint3d(center);
209     mRelativeLightCenter = center;
210 
211     transform = &mTransformRoot;
212     transform->loadTranslate(x, y, z);
213 }
214 
215 ///////////////////////////////////////////////////////////////////////////////
216 // Clipping round rect
217 ///////////////////////////////////////////////////////////////////////////////
218 
setClippingRoundRect(LinearAllocator & allocator,const Rect & bounds,float radius,bool highPriority)219 void Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds,
220         float radius, bool highPriority) {
221     if (bounds.isEmpty()) {
222         clipRect->setEmpty();
223         return;
224     }
225 
226     if (roundRectClipState && roundRectClipState->highPriority) {
227         // ignore, don't replace, already have a high priority clip
228         return;
229     }
230 
231     RoundRectClipState* state = new (allocator) RoundRectClipState;
232 
233     state->highPriority = highPriority;
234 
235     // store the inverse drawing matrix
236     Matrix4 roundRectDrawingMatrix;
237     roundRectDrawingMatrix.load(getOrthoMatrix());
238     roundRectDrawingMatrix.multiply(*transform);
239     state->matrix.loadInverse(roundRectDrawingMatrix);
240 
241     // compute area under rounded corners - only draws overlapping these rects need to be clipped
242     for (int i = 0 ; i < 4; i++) {
243         state->dangerRects[i] = bounds;
244     }
245     state->dangerRects[0].bottom = state->dangerRects[1].bottom = bounds.top + radius;
246     state->dangerRects[0].right = state->dangerRects[2].right = bounds.left + radius;
247     state->dangerRects[1].left = state->dangerRects[3].left = bounds.right - radius;
248     state->dangerRects[2].top = state->dangerRects[3].top = bounds.bottom - radius;
249     for (int i = 0; i < 4; i++) {
250         transform->mapRect(state->dangerRects[i]);
251 
252         // round danger rects out as though they are AA geometry (since they essentially are)
253         state->dangerRects[i].snapGeometryToPixelBoundaries(true);
254     }
255 
256     // store RR area
257     state->innerRect = bounds;
258     state->innerRect.inset(radius);
259     state->radius = radius;
260 
261     // store as immutable so, for this frame, pointer uniquely identifies this bundle of shader info
262     roundRectClipState = state;
263 }
264 
265 ///////////////////////////////////////////////////////////////////////////////
266 // Queries
267 ///////////////////////////////////////////////////////////////////////////////
268 
isIgnored() const269 bool Snapshot::isIgnored() const {
270     return invisible || empty;
271 }
272 
dump() const273 void Snapshot::dump() const {
274     ALOGD("Snapshot %p, flags %x, prev %p, height %d, ignored %d, hasComplexClip %d",
275             this, flags, previous.get(), getViewportHeight(), isIgnored(), clipRegion && !clipRegion->isEmpty());
276     ALOGD("  ClipRect (at %p) %.1f %.1f %.1f %.1f",
277             clipRect, clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
278     ALOGD("  Transform (at %p):", transform);
279     transform->dump();
280 }
281 
282 }; // namespace uirenderer
283 }; // namespace android
284