blob: 0a58f4b42e4cb8026e102811c0b97b126c7e01a2 [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
19#include <SkCanvas.h>
20
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;
Romain Guyada4d532012-02-02 17:31:16 -080041}
42
43/**
44 * Copies the specified snapshot/ The specified snapshot is stored as
45 * the previous snapshot.
46 */
John Reckd9ee5502015-10-06 10:06:37 -070047Snapshot::Snapshot(Snapshot* s, int saveFlags)
Chris Craike4aa95e2014-05-08 13:57:05 -070048 : flags(0)
49 , previous(s)
50 , layer(s->layer)
51 , fbo(s->fbo)
52 , invisible(s->invisible)
53 , empty(false)
Chris Craika64a2be2014-05-14 14:17:01 -070054 , alpha(s->alpha)
Chris Craikdeeda3d2014-05-05 19:09:33 -070055 , roundRectClipState(s->roundRectClipState)
Chris Craikfca52b752015-04-28 11:45:59 -070056 , projectionPathMask(s->projectionPathMask)
Rob Tsuk487a92c2015-01-06 13:22:54 -080057 , mClipArea(nullptr)
Chris Craik69e5adf2014-08-14 13:34:01 -070058 , mViewportData(s->mViewportData)
59 , mRelativeLightCenter(s->mRelativeLightCenter) {
Romain Guyada4d532012-02-02 17:31:16 -080060 if (saveFlags & SkCanvas::kMatrix_SaveFlag) {
Chris Craik7c85c542015-08-19 15:10:24 -070061 mTransformRoot = *s->transform;
Romain Guyada4d532012-02-02 17:31:16 -080062 transform = &mTransformRoot;
63 } else {
64 transform = s->transform;
65 }
66
67 if (saveFlags & SkCanvas::kClip_SaveFlag) {
Rob Tsuk487a92c2015-01-06 13:22:54 -080068 mClipAreaRoot = s->getClipArea();
69 mClipArea = &mClipAreaRoot;
Romain Guyada4d532012-02-02 17:31:16 -080070 } else {
Rob Tsuk487a92c2015-01-06 13:22:54 -080071 mClipArea = s->mClipArea;
Romain Guyada4d532012-02-02 17:31:16 -080072 }
73
74 if (s->flags & Snapshot::kFlagFboTarget) {
75 flags |= Snapshot::kFlagFboTarget;
76 region = s->region;
77 } else {
Chris Craikd41c4d82015-01-05 15:51:13 -080078 region = nullptr;
Romain Guyada4d532012-02-02 17:31:16 -080079 }
80}
81
82///////////////////////////////////////////////////////////////////////////////
83// Clipping
84///////////////////////////////////////////////////////////////////////////////
85
Chris Craik4d3e7042015-08-20 12:54:25 -070086void Snapshot::clipRegionTransformed(const SkRegion& region, SkRegion::Op op) {
Romain Guy8ce00302013-01-15 18:51:42 -080087 flags |= Snapshot::kFlagClipSet;
Chris Craik4d3e7042015-08-20 12:54:25 -070088 mClipArea->clipRegion(region, op);
Romain Guy967e2bf2012-02-07 17:04:34 -080089}
90
Chris Craik4d3e7042015-08-20 12:54:25 -070091void Snapshot::clip(float left, float top, float right, float bottom, SkRegion::Op op) {
Rob Tsuk487a92c2015-01-06 13:22:54 -080092 flags |= Snapshot::kFlagClipSet;
Chris Craik4d3e7042015-08-20 12:54:25 -070093 mClipArea->clipRectWithTransform(left, top, right, bottom, transform, op);
Romain Guyada4d532012-02-02 17:31:16 -080094}
95
Chris Craik4d3e7042015-08-20 12:54:25 -070096void Snapshot::clipPath(const SkPath& path, SkRegion::Op op) {
Rob Tsuk487a92c2015-01-06 13:22:54 -080097 flags |= Snapshot::kFlagClipSet;
Chris Craik4d3e7042015-08-20 12:54:25 -070098 mClipArea->clipPathWithTransform(path, transform, op);
Romain Guyada4d532012-02-02 17:31:16 -080099}
100
101void Snapshot::setClip(float left, float top, float right, float bottom) {
Romain Guyada4d532012-02-02 17:31:16 -0800102 flags |= Snapshot::kFlagClipSet;
Chris Craik4d3e7042015-08-20 12:54:25 -0700103 mClipArea->setClip(left, top, right, bottom);
Romain Guyada4d532012-02-02 17:31:16 -0800104}
105
Romain Guya3dc55f2012-09-28 13:55:44 -0700106bool Snapshot::hasPerspectiveTransform() const {
107 return transform->isPerspective();
108}
109
Romain Guyada4d532012-02-02 17:31:16 -0800110const Rect& Snapshot::getLocalClip() {
111 mat4 inverse;
112 inverse.loadInverse(*transform);
113
Rob Tsuk487a92c2015-01-06 13:22:54 -0800114 mLocalClip.set(mClipArea->getClipRect());
Romain Guyada4d532012-02-02 17:31:16 -0800115 inverse.mapRect(mLocalClip);
116
117 return mLocalClip;
118}
119
120void Snapshot::resetClip(float left, float top, float right, float bottom) {
Romain Guy3bbacf22013-02-06 16:51:04 -0800121 // TODO: This is incorrect, when we start rendering into a new layer,
122 // we may have to modify the previous snapshot's clip rect and clip
123 // region if the previous restore() call did not restore the clip
Rob Tsuk487a92c2015-01-06 13:22:54 -0800124 mClipArea = &mClipAreaRoot;
Romain Guy967e2bf2012-02-07 17:04:34 -0800125 setClip(left, top, right, bottom);
Romain Guyada4d532012-02-02 17:31:16 -0800126}
127
128///////////////////////////////////////////////////////////////////////////////
129// Transforms
130///////////////////////////////////////////////////////////////////////////////
131
132void Snapshot::resetTransform(float x, float y, float z) {
Chris Craik69e5adf2014-08-14 13:34:01 -0700133 // before resetting, map current light pos with inverse of current transform
134 Vector3 center = mRelativeLightCenter;
135 mat4 inverse;
136 inverse.loadInverse(*transform);
137 inverse.mapPoint3d(center);
138 mRelativeLightCenter = center;
139
Romain Guyada4d532012-02-02 17:31:16 -0800140 transform = &mTransformRoot;
141 transform->loadTranslate(x, y, z);
142}
143
Chris Craikfca52b752015-04-28 11:45:59 -0700144void Snapshot::buildScreenSpaceTransform(Matrix4* outTransform) const {
145 // build (reverse ordered) list of the stack of snapshots, terminated with a NULL
146 Vector<const Snapshot*> snapshotList;
147 snapshotList.push(nullptr);
148 const Snapshot* current = this;
149 do {
150 snapshotList.push(current);
John Reckd9ee5502015-10-06 10:06:37 -0700151 current = current->previous;
Chris Craikfca52b752015-04-28 11:45:59 -0700152 } while (current);
153
154 // traverse the list, adding in each transform that contributes to the total transform
155 outTransform->loadIdentity();
156 for (size_t i = snapshotList.size() - 1; i > 0; i--) {
157 // iterate down the stack
158 const Snapshot* current = snapshotList[i];
159 const Snapshot* next = snapshotList[i - 1];
160 if (current->flags & kFlagIsFboLayer) {
161 // if we've hit a layer, translate by the layer's draw offset
162 outTransform->translate(current->layer->layer.left, current->layer->layer.top);
163 }
164 if (!next || (next->flags & kFlagIsFboLayer)) {
165 // if this snapshot is last, or if this snapshot is last before an
166 // FBO layer (which reset the transform), apply it
167 outTransform->multiply(*(current->transform));
168 }
169 }
170}
171
Romain Guyada4d532012-02-02 17:31:16 -0800172///////////////////////////////////////////////////////////////////////////////
Chris Craikaf4d04c2014-07-29 12:50:14 -0700173// Clipping round rect
Chris Craikdeeda3d2014-05-05 19:09:33 -0700174///////////////////////////////////////////////////////////////////////////////
175
Chris Craike83cbd42014-09-03 17:52:24 -0700176void Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds,
177 float radius, bool highPriority) {
Chris Craikaf4d04c2014-07-29 12:50:14 -0700178 if (bounds.isEmpty()) {
Rob Tsuk487a92c2015-01-06 13:22:54 -0800179 mClipArea->setEmpty();
Chris Craikaf4d04c2014-07-29 12:50:14 -0700180 return;
181 }
Chris Craikdeeda3d2014-05-05 19:09:33 -0700182
Chris Craike83cbd42014-09-03 17:52:24 -0700183 if (roundRectClipState && roundRectClipState->highPriority) {
184 // ignore, don't replace, already have a high priority clip
185 return;
186 }
187
Chris Craikdeeda3d2014-05-05 19:09:33 -0700188 RoundRectClipState* state = new (allocator) RoundRectClipState;
189
Chris Craike83cbd42014-09-03 17:52:24 -0700190 state->highPriority = highPriority;
191
Chris Craikdeeda3d2014-05-05 19:09:33 -0700192 // store the inverse drawing matrix
Chris Craik7c85c542015-08-19 15:10:24 -0700193 Matrix4 roundRectDrawingMatrix = getOrthoMatrix();
Chris Craikaf4d04c2014-07-29 12:50:14 -0700194 roundRectDrawingMatrix.multiply(*transform);
195 state->matrix.loadInverse(roundRectDrawingMatrix);
Chris Craikdeeda3d2014-05-05 19:09:33 -0700196
197 // compute area under rounded corners - only draws overlapping these rects need to be clipped
198 for (int i = 0 ; i < 4; i++) {
199 state->dangerRects[i] = bounds;
200 }
201 state->dangerRects[0].bottom = state->dangerRects[1].bottom = bounds.top + radius;
202 state->dangerRects[0].right = state->dangerRects[2].right = bounds.left + radius;
203 state->dangerRects[1].left = state->dangerRects[3].left = bounds.right - radius;
204 state->dangerRects[2].top = state->dangerRects[3].top = bounds.bottom - radius;
205 for (int i = 0; i < 4; i++) {
206 transform->mapRect(state->dangerRects[i]);
207
208 // round danger rects out as though they are AA geometry (since they essentially are)
209 state->dangerRects[i].snapGeometryToPixelBoundaries(true);
210 }
211
212 // store RR area
Chris Craikaf4d04c2014-07-29 12:50:14 -0700213 state->innerRect = bounds;
214 state->innerRect.inset(radius);
215 state->radius = radius;
Chris Craikdeeda3d2014-05-05 19:09:33 -0700216
217 // store as immutable so, for this frame, pointer uniquely identifies this bundle of shader info
218 roundRectClipState = state;
219}
220
Chris Craikfca52b752015-04-28 11:45:59 -0700221void Snapshot::setProjectionPathMask(LinearAllocator& allocator, const SkPath* path) {
222 if (path) {
223 ProjectionPathMask* mask = new (allocator) ProjectionPathMask;
224 mask->projectionMask = path;
225 buildScreenSpaceTransform(&(mask->projectionMaskTransform));
226
227 projectionPathMask = mask;
228 } else {
229 projectionPathMask = nullptr;
230 }
231}
232
Chris Craikdeeda3d2014-05-05 19:09:33 -0700233///////////////////////////////////////////////////////////////////////////////
Romain Guyada4d532012-02-02 17:31:16 -0800234// Queries
235///////////////////////////////////////////////////////////////////////////////
236
237bool Snapshot::isIgnored() const {
238 return invisible || empty;
239}
240
Chris Craik5f803622013-03-21 14:39:04 -0700241void Snapshot::dump() const {
242 ALOGD("Snapshot %p, flags %x, prev %p, height %d, ignored %d, hasComplexClip %d",
John Reckd9ee5502015-10-06 10:06:37 -0700243 this, flags, previous, getViewportHeight(), isIgnored(), !mClipArea->isSimple());
Rob Tsuk487a92c2015-01-06 13:22:54 -0800244 const Rect& clipRect(mClipArea->getClipRect());
Chris Craike9c01a42015-04-06 10:47:23 -0700245 ALOGD(" ClipRect %.1f %.1f %.1f %.1f, clip simple %d",
246 clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, mClipArea->isSimple());
247
Chris Craik5f803622013-03-21 14:39:04 -0700248 ALOGD(" Transform (at %p):", transform);
249 transform->dump();
250}
251
Romain Guyada4d532012-02-02 17:31:16 -0800252}; // namespace uirenderer
253}; // namespace android