blob: 7c187fbda457302dfd4b5e9c22aa6cbf447c002f [file] [log] [blame]
Romain Guyada4d532012-02-02 17:31:16 -08001/*
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#include "Snapshot.h"
18
sergeyvdccca442016-03-21 15:38:21 -070019#include "hwui/Canvas.h"
Romain Guyada4d532012-02-02 17:31:16 -080020
21namespace android {
22namespace uirenderer {
23
24///////////////////////////////////////////////////////////////////////////////
25// Constructors
26///////////////////////////////////////////////////////////////////////////////
27
Chris Craike4aa95e2014-05-08 13:57:05 -070028Snapshot::Snapshot()
29 : flags(0)
Chris Craikd41c4d82015-01-05 15:51:13 -080030 , previous(nullptr)
31 , layer(nullptr)
Chris Craike4aa95e2014-05-08 13:57:05 -070032 , fbo(0)
33 , invisible(false)
34 , empty(false)
Chris Craikdeeda3d2014-05-05 19:09:33 -070035 , alpha(1.0f)
Rob Tsuk487a92c2015-01-06 13:22:54 -080036 , roundRectClipState(nullptr)
Chris Craikfca52b752015-04-28 11:45:59 -070037 , projectionPathMask(nullptr)
Rob Tsuk487a92c2015-01-06 13:22:54 -080038 , mClipArea(&mClipAreaRoot) {
Romain Guyada4d532012-02-02 17:31:16 -080039 transform = &mTransformRoot;
Chris Craikd41c4d82015-01-05 15:51:13 -080040 region = nullptr;
Keith Mokde89c2f2016-07-13 14:45:16 -070041 mRelativeLightCenter.x = mRelativeLightCenter.y = mRelativeLightCenter.z = 0;
Romain Guyada4d532012-02-02 17:31:16 -080042}
43
44/**
45 * Copies the specified snapshot/ The specified snapshot is stored as
46 * the previous snapshot.
47 */
John Reckd9ee5502015-10-06 10:06:37 -070048Snapshot::Snapshot(Snapshot* s, int saveFlags)
Chris Craike4aa95e2014-05-08 13:57:05 -070049 : flags(0)
50 , previous(s)
51 , layer(s->layer)
52 , fbo(s->fbo)
53 , invisible(s->invisible)
54 , empty(false)
Chris Craika64a2be2014-05-14 14:17:01 -070055 , alpha(s->alpha)
Chris Craikdeeda3d2014-05-05 19:09:33 -070056 , roundRectClipState(s->roundRectClipState)
Chris Craikfca52b752015-04-28 11:45:59 -070057 , projectionPathMask(s->projectionPathMask)
Rob Tsuk487a92c2015-01-06 13:22:54 -080058 , mClipArea(nullptr)
Chris Craik69e5adf2014-08-14 13:34:01 -070059 , mViewportData(s->mViewportData)
60 , mRelativeLightCenter(s->mRelativeLightCenter) {
Florin Malitaeecff562015-12-21 10:43:01 -050061 if (saveFlags & SaveFlags::Matrix) {
Chris Craik7c85c542015-08-19 15:10:24 -070062 mTransformRoot = *s->transform;
Romain Guyada4d532012-02-02 17:31:16 -080063 transform = &mTransformRoot;
64 } else {
65 transform = s->transform;
66 }
67
Florin Malitaeecff562015-12-21 10:43:01 -050068 if (saveFlags & SaveFlags::Clip) {
Rob Tsuk487a92c2015-01-06 13:22:54 -080069 mClipAreaRoot = s->getClipArea();
70 mClipArea = &mClipAreaRoot;
Romain Guyada4d532012-02-02 17:31:16 -080071 } else {
Rob Tsuk487a92c2015-01-06 13:22:54 -080072 mClipArea = s->mClipArea;
Romain Guyada4d532012-02-02 17:31:16 -080073 }
74
75 if (s->flags & Snapshot::kFlagFboTarget) {
76 flags |= Snapshot::kFlagFboTarget;
77 region = s->region;
78 } else {
Chris Craikd41c4d82015-01-05 15:51:13 -080079 region = nullptr;
Romain Guyada4d532012-02-02 17:31:16 -080080 }
81}
82
83///////////////////////////////////////////////////////////////////////////////
84// Clipping
85///////////////////////////////////////////////////////////////////////////////
86
Chris Craik4d3e7042015-08-20 12:54:25 -070087void Snapshot::clipRegionTransformed(const SkRegion& region, SkRegion::Op op) {
Romain Guy8ce00302013-01-15 18:51:42 -080088 flags |= Snapshot::kFlagClipSet;
Chris Craik4d3e7042015-08-20 12:54:25 -070089 mClipArea->clipRegion(region, op);
Romain Guy967e2bf2012-02-07 17:04:34 -080090}
91
Chris Craika2a70722015-12-17 12:58:24 -080092void Snapshot::clip(const Rect& localClip, SkRegion::Op op) {
Rob Tsuk487a92c2015-01-06 13:22:54 -080093 flags |= Snapshot::kFlagClipSet;
Chris Craika2a70722015-12-17 12:58:24 -080094 mClipArea->clipRectWithTransform(localClip, transform, op);
Romain Guyada4d532012-02-02 17:31:16 -080095}
96
Chris Craik4d3e7042015-08-20 12:54:25 -070097void Snapshot::clipPath(const SkPath& path, SkRegion::Op op) {
Rob Tsuk487a92c2015-01-06 13:22:54 -080098 flags |= Snapshot::kFlagClipSet;
Chris Craik4d3e7042015-08-20 12:54:25 -070099 mClipArea->clipPathWithTransform(path, transform, op);
Romain Guyada4d532012-02-02 17:31:16 -0800100}
101
102void Snapshot::setClip(float left, float top, float right, float bottom) {
Romain Guyada4d532012-02-02 17:31:16 -0800103 flags |= Snapshot::kFlagClipSet;
Chris Craik4d3e7042015-08-20 12:54:25 -0700104 mClipArea->setClip(left, top, right, bottom);
Romain Guyada4d532012-02-02 17:31:16 -0800105}
106
Romain Guya3dc55f2012-09-28 13:55:44 -0700107bool Snapshot::hasPerspectiveTransform() const {
108 return transform->isPerspective();
109}
110
Romain Guyada4d532012-02-02 17:31:16 -0800111const Rect& Snapshot::getLocalClip() {
112 mat4 inverse;
113 inverse.loadInverse(*transform);
114
Rob Tsuk487a92c2015-01-06 13:22:54 -0800115 mLocalClip.set(mClipArea->getClipRect());
Romain Guyada4d532012-02-02 17:31:16 -0800116 inverse.mapRect(mLocalClip);
117
118 return mLocalClip;
119}
120
121void Snapshot::resetClip(float left, float top, float right, float bottom) {
Romain Guy3bbacf22013-02-06 16:51:04 -0800122 // TODO: This is incorrect, when we start rendering into a new layer,
123 // we may have to modify the previous snapshot's clip rect and clip
124 // region if the previous restore() call did not restore the clip
Rob Tsuk487a92c2015-01-06 13:22:54 -0800125 mClipArea = &mClipAreaRoot;
Romain Guy967e2bf2012-02-07 17:04:34 -0800126 setClip(left, top, right, bottom);
Romain Guyada4d532012-02-02 17:31:16 -0800127}
128
129///////////////////////////////////////////////////////////////////////////////
130// Transforms
131///////////////////////////////////////////////////////////////////////////////
132
133void Snapshot::resetTransform(float x, float y, float z) {
Chris Craik98787e62015-11-13 10:55:30 -0800134#if HWUI_NEW_OPS
135 LOG_ALWAYS_FATAL("not supported - light center managed differently");
136#else
Chris Craik69e5adf2014-08-14 13:34:01 -0700137 // before resetting, map current light pos with inverse of current transform
138 Vector3 center = mRelativeLightCenter;
139 mat4 inverse;
140 inverse.loadInverse(*transform);
141 inverse.mapPoint3d(center);
142 mRelativeLightCenter = center;
143
Romain Guyada4d532012-02-02 17:31:16 -0800144 transform = &mTransformRoot;
145 transform->loadTranslate(x, y, z);
Chris Craik98787e62015-11-13 10:55:30 -0800146#endif
Romain Guyada4d532012-02-02 17:31:16 -0800147}
148
Chris Craikfca52b752015-04-28 11:45:59 -0700149void Snapshot::buildScreenSpaceTransform(Matrix4* outTransform) const {
Chris Craik678ff812016-03-01 13:27:54 -0800150#if HWUI_NEW_OPS
151 LOG_ALWAYS_FATAL("not supported - not needed by new ops");
152#else
Chris Craikfca52b752015-04-28 11:45:59 -0700153 // build (reverse ordered) list of the stack of snapshots, terminated with a NULL
154 Vector<const Snapshot*> snapshotList;
155 snapshotList.push(nullptr);
156 const Snapshot* current = this;
157 do {
158 snapshotList.push(current);
John Reckd9ee5502015-10-06 10:06:37 -0700159 current = current->previous;
Chris Craikfca52b752015-04-28 11:45:59 -0700160 } while (current);
161
162 // traverse the list, adding in each transform that contributes to the total transform
163 outTransform->loadIdentity();
164 for (size_t i = snapshotList.size() - 1; i > 0; i--) {
165 // iterate down the stack
166 const Snapshot* current = snapshotList[i];
167 const Snapshot* next = snapshotList[i - 1];
168 if (current->flags & kFlagIsFboLayer) {
169 // if we've hit a layer, translate by the layer's draw offset
170 outTransform->translate(current->layer->layer.left, current->layer->layer.top);
171 }
172 if (!next || (next->flags & kFlagIsFboLayer)) {
173 // if this snapshot is last, or if this snapshot is last before an
174 // FBO layer (which reset the transform), apply it
175 outTransform->multiply(*(current->transform));
176 }
177 }
Chris Craik678ff812016-03-01 13:27:54 -0800178#endif
Chris Craikfca52b752015-04-28 11:45:59 -0700179}
180
Romain Guyada4d532012-02-02 17:31:16 -0800181///////////////////////////////////////////////////////////////////////////////
Chris Craikaf4d04c2014-07-29 12:50:14 -0700182// Clipping round rect
Chris Craikdeeda3d2014-05-05 19:09:33 -0700183///////////////////////////////////////////////////////////////////////////////
184
Chris Craike83cbd42014-09-03 17:52:24 -0700185void Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds,
186 float radius, bool highPriority) {
Chris Craikaf4d04c2014-07-29 12:50:14 -0700187 if (bounds.isEmpty()) {
Rob Tsuk487a92c2015-01-06 13:22:54 -0800188 mClipArea->setEmpty();
Chris Craikaf4d04c2014-07-29 12:50:14 -0700189 return;
190 }
Chris Craikdeeda3d2014-05-05 19:09:33 -0700191
Chris Craike83cbd42014-09-03 17:52:24 -0700192 if (roundRectClipState && roundRectClipState->highPriority) {
193 // ignore, don't replace, already have a high priority clip
194 return;
195 }
196
Chris Craikdeeda3d2014-05-05 19:09:33 -0700197 RoundRectClipState* state = new (allocator) RoundRectClipState;
198
Chris Craike83cbd42014-09-03 17:52:24 -0700199 state->highPriority = highPriority;
200
Chris Craikdeeda3d2014-05-05 19:09:33 -0700201 // store the inverse drawing matrix
Chris Craik7c85c542015-08-19 15:10:24 -0700202 Matrix4 roundRectDrawingMatrix = getOrthoMatrix();
Chris Craikaf4d04c2014-07-29 12:50:14 -0700203 roundRectDrawingMatrix.multiply(*transform);
204 state->matrix.loadInverse(roundRectDrawingMatrix);
Chris Craikdeeda3d2014-05-05 19:09:33 -0700205
206 // compute area under rounded corners - only draws overlapping these rects need to be clipped
207 for (int i = 0 ; i < 4; i++) {
208 state->dangerRects[i] = bounds;
209 }
210 state->dangerRects[0].bottom = state->dangerRects[1].bottom = bounds.top + radius;
211 state->dangerRects[0].right = state->dangerRects[2].right = bounds.left + radius;
212 state->dangerRects[1].left = state->dangerRects[3].left = bounds.right - radius;
213 state->dangerRects[2].top = state->dangerRects[3].top = bounds.bottom - radius;
214 for (int i = 0; i < 4; i++) {
215 transform->mapRect(state->dangerRects[i]);
216
217 // round danger rects out as though they are AA geometry (since they essentially are)
218 state->dangerRects[i].snapGeometryToPixelBoundaries(true);
219 }
220
221 // store RR area
Chris Craikaf4d04c2014-07-29 12:50:14 -0700222 state->innerRect = bounds;
223 state->innerRect.inset(radius);
224 state->radius = radius;
Chris Craikdeeda3d2014-05-05 19:09:33 -0700225
226 // store as immutable so, for this frame, pointer uniquely identifies this bundle of shader info
227 roundRectClipState = state;
228}
229
Chris Craikfca52b752015-04-28 11:45:59 -0700230void Snapshot::setProjectionPathMask(LinearAllocator& allocator, const SkPath* path) {
Chris Craik678ff812016-03-01 13:27:54 -0800231#if HWUI_NEW_OPS
232 // TODO: remove allocator param for HWUI_NEW_OPS
233 projectionPathMask = path;
234#else
Chris Craikfca52b752015-04-28 11:45:59 -0700235 if (path) {
236 ProjectionPathMask* mask = new (allocator) ProjectionPathMask;
237 mask->projectionMask = path;
238 buildScreenSpaceTransform(&(mask->projectionMaskTransform));
Chris Craikfca52b752015-04-28 11:45:59 -0700239 projectionPathMask = mask;
240 } else {
241 projectionPathMask = nullptr;
242 }
Chris Craik678ff812016-03-01 13:27:54 -0800243#endif
Chris Craikfca52b752015-04-28 11:45:59 -0700244}
245
Chris Craik04d46eb2016-04-07 13:51:07 -0700246static Snapshot* getClipRoot(Snapshot* target) {
247 while (target->previous && target->previous->previous) {
248 target = target->previous;
249 }
250 return target;
251}
252
253const ClipBase* Snapshot::serializeIntersectedClip(LinearAllocator& allocator,
254 const ClipBase* recordedClip, const Matrix4& recordedClipTransform) {
255 auto target = this;
256 if (CC_UNLIKELY(recordedClip && recordedClip->intersectWithRoot)) {
257 // Clip must be intersected with root, instead of current clip.
258 target = getClipRoot(this);
259 }
260
261 return target->mClipArea->serializeIntersectedClip(allocator,
262 recordedClip, recordedClipTransform);
263}
264
265void Snapshot::applyClip(const ClipBase* recordedClip, const Matrix4& transform) {
266 if (CC_UNLIKELY(recordedClip && recordedClip->intersectWithRoot)) {
267 // current clip is being replaced, but must intersect with clip root
268 *mClipArea = *(getClipRoot(this)->mClipArea);
269 }
270 mClipArea->applyClip(recordedClip, transform);
271}
272
Chris Craikdeeda3d2014-05-05 19:09:33 -0700273///////////////////////////////////////////////////////////////////////////////
Romain Guyada4d532012-02-02 17:31:16 -0800274// Queries
275///////////////////////////////////////////////////////////////////////////////
276
277bool Snapshot::isIgnored() const {
278 return invisible || empty;
279}
280
Chris Craik5f803622013-03-21 14:39:04 -0700281void Snapshot::dump() const {
282 ALOGD("Snapshot %p, flags %x, prev %p, height %d, ignored %d, hasComplexClip %d",
John Reckd9ee5502015-10-06 10:06:37 -0700283 this, flags, previous, getViewportHeight(), isIgnored(), !mClipArea->isSimple());
Rob Tsuk487a92c2015-01-06 13:22:54 -0800284 const Rect& clipRect(mClipArea->getClipRect());
Chris Craike9c01a42015-04-06 10:47:23 -0700285 ALOGD(" ClipRect %.1f %.1f %.1f %.1f, clip simple %d",
286 clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, mClipArea->isSimple());
287
Chris Craik5f803622013-03-21 14:39:04 -0700288 ALOGD(" Transform (at %p):", transform);
289 transform->dump();
290}
291
Romain Guyada4d532012-02-02 17:31:16 -0800292}; // namespace uirenderer
293}; // namespace android