blob: 3da3a572fd0a6d474a33b4d148d1134cfd935b44 [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
Chris Craik5f803622013-03-21 14:39:04 -070017#define LOG_TAG "OpenGLRenderer"
18
Romain Guyada4d532012-02-02 17:31:16 -080019#include "Snapshot.h"
20
21#include <SkCanvas.h>
22
23namespace android {
24namespace uirenderer {
25
26///////////////////////////////////////////////////////////////////////////////
27// Constructors
28///////////////////////////////////////////////////////////////////////////////
29
Chris Craike4aa95e2014-05-08 13:57:05 -070030Snapshot::Snapshot()
31 : flags(0)
Chris Craikd41c4d82015-01-05 15:51:13 -080032 , previous(nullptr)
33 , layer(nullptr)
Chris Craike4aa95e2014-05-08 13:57:05 -070034 , fbo(0)
35 , invisible(false)
36 , empty(false)
Chris Craikdeeda3d2014-05-05 19:09:33 -070037 , alpha(1.0f)
Rob Tsuk487a92c2015-01-06 13:22:54 -080038 , roundRectClipState(nullptr)
Chris Craikfca52b752015-04-28 11:45:59 -070039 , projectionPathMask(nullptr)
Rob Tsuk487a92c2015-01-06 13:22:54 -080040 , mClipArea(&mClipAreaRoot) {
Romain Guyada4d532012-02-02 17:31:16 -080041 transform = &mTransformRoot;
Chris Craikd41c4d82015-01-05 15:51:13 -080042 region = nullptr;
Keith Mokde89c2f2016-07-13 14:45:16 -070043 mRelativeLightCenter.x = mRelativeLightCenter.y = mRelativeLightCenter.z = 0;
Romain Guyada4d532012-02-02 17:31:16 -080044}
45
46/**
47 * Copies the specified snapshot/ The specified snapshot is stored as
48 * the previous snapshot.
49 */
Chris Craike4aa95e2014-05-08 13:57:05 -070050Snapshot::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)
Chris Craika64a2be2014-05-14 14:17:01 -070057 , alpha(s->alpha)
Chris Craikdeeda3d2014-05-05 19:09:33 -070058 , roundRectClipState(s->roundRectClipState)
Chris Craikfca52b752015-04-28 11:45:59 -070059 , projectionPathMask(s->projectionPathMask)
Rob Tsuk487a92c2015-01-06 13:22:54 -080060 , mClipArea(nullptr)
Chris Craik69e5adf2014-08-14 13:34:01 -070061 , mViewportData(s->mViewportData)
62 , mRelativeLightCenter(s->mRelativeLightCenter) {
Romain Guyada4d532012-02-02 17:31:16 -080063 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) {
Rob Tsuk487a92c2015-01-06 13:22:54 -080071 mClipAreaRoot = s->getClipArea();
72 mClipArea = &mClipAreaRoot;
Romain Guyada4d532012-02-02 17:31:16 -080073 } else {
Rob Tsuk487a92c2015-01-06 13:22:54 -080074 mClipArea = s->mClipArea;
Romain Guyada4d532012-02-02 17:31:16 -080075 }
76
77 if (s->flags & Snapshot::kFlagFboTarget) {
78 flags |= Snapshot::kFlagFboTarget;
79 region = s->region;
80 } else {
Chris Craikd41c4d82015-01-05 15:51:13 -080081 region = nullptr;
Romain Guyada4d532012-02-02 17:31:16 -080082 }
83}
84
85///////////////////////////////////////////////////////////////////////////////
86// Clipping
87///////////////////////////////////////////////////////////////////////////////
88
Romain Guy8ce00302013-01-15 18:51:42 -080089bool Snapshot::clipRegionTransformed(const SkRegion& region, SkRegion::Op op) {
Romain Guy8ce00302013-01-15 18:51:42 -080090 flags |= Snapshot::kFlagClipSet;
Rob Tsuk487a92c2015-01-06 13:22:54 -080091 return mClipArea->clipRegion(region, op);
Romain Guy967e2bf2012-02-07 17:04:34 -080092}
93
Romain Guyada4d532012-02-02 17:31:16 -080094bool Snapshot::clip(float left, float top, float right, float bottom, SkRegion::Op op) {
Rob Tsuk487a92c2015-01-06 13:22:54 -080095 flags |= Snapshot::kFlagClipSet;
96 return mClipArea->clipRectWithTransform(left, top, right, bottom, transform, op);
Romain Guyada4d532012-02-02 17:31:16 -080097}
98
Rob Tsuk487a92c2015-01-06 13:22:54 -080099bool Snapshot::clipPath(const SkPath& path, SkRegion::Op op) {
100 flags |= Snapshot::kFlagClipSet;
101 return mClipArea->clipPathWithTransform(path, transform, op);
Romain Guyada4d532012-02-02 17:31:16 -0800102}
103
104void Snapshot::setClip(float left, float top, float right, float bottom) {
Rob Tsuk487a92c2015-01-06 13:22:54 -0800105 mClipArea->setClip(left, top, right, bottom);
Romain Guyada4d532012-02-02 17:31:16 -0800106 flags |= Snapshot::kFlagClipSet;
107}
108
Romain Guya3dc55f2012-09-28 13:55:44 -0700109bool Snapshot::hasPerspectiveTransform() const {
110 return transform->isPerspective();
111}
112
Romain Guyada4d532012-02-02 17:31:16 -0800113const Rect& Snapshot::getLocalClip() {
114 mat4 inverse;
115 inverse.loadInverse(*transform);
116
Rob Tsuk487a92c2015-01-06 13:22:54 -0800117 mLocalClip.set(mClipArea->getClipRect());
Romain Guyada4d532012-02-02 17:31:16 -0800118 inverse.mapRect(mLocalClip);
119
120 return mLocalClip;
121}
122
123void Snapshot::resetClip(float left, float top, float right, float bottom) {
Romain Guy3bbacf22013-02-06 16:51:04 -0800124 // 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
Rob Tsuk487a92c2015-01-06 13:22:54 -0800127 mClipArea = &mClipAreaRoot;
Romain Guy967e2bf2012-02-07 17:04:34 -0800128 setClip(left, top, right, bottom);
Romain Guyada4d532012-02-02 17:31:16 -0800129}
130
131///////////////////////////////////////////////////////////////////////////////
132// Transforms
133///////////////////////////////////////////////////////////////////////////////
134
135void Snapshot::resetTransform(float x, float y, float z) {
Chris Craik69e5adf2014-08-14 13:34:01 -0700136 // 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
Romain Guyada4d532012-02-02 17:31:16 -0800143 transform = &mTransformRoot;
144 transform->loadTranslate(x, y, z);
145}
146
Chris Craikfca52b752015-04-28 11:45:59 -0700147void 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
Romain Guyada4d532012-02-02 17:31:16 -0800175///////////////////////////////////////////////////////////////////////////////
Chris Craikaf4d04c2014-07-29 12:50:14 -0700176// Clipping round rect
Chris Craikdeeda3d2014-05-05 19:09:33 -0700177///////////////////////////////////////////////////////////////////////////////
178
Chris Craike83cbd42014-09-03 17:52:24 -0700179void Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds,
180 float radius, bool highPriority) {
Chris Craikaf4d04c2014-07-29 12:50:14 -0700181 if (bounds.isEmpty()) {
Rob Tsuk487a92c2015-01-06 13:22:54 -0800182 mClipArea->setEmpty();
Chris Craikaf4d04c2014-07-29 12:50:14 -0700183 return;
184 }
Chris Craikdeeda3d2014-05-05 19:09:33 -0700185
Chris Craike83cbd42014-09-03 17:52:24 -0700186 if (roundRectClipState && roundRectClipState->highPriority) {
187 // ignore, don't replace, already have a high priority clip
188 return;
189 }
190
Chris Craikdeeda3d2014-05-05 19:09:33 -0700191 RoundRectClipState* state = new (allocator) RoundRectClipState;
192
Chris Craike83cbd42014-09-03 17:52:24 -0700193 state->highPriority = highPriority;
194
Chris Craikdeeda3d2014-05-05 19:09:33 -0700195 // store the inverse drawing matrix
Chris Craikaf4d04c2014-07-29 12:50:14 -0700196 Matrix4 roundRectDrawingMatrix;
197 roundRectDrawingMatrix.load(getOrthoMatrix());
198 roundRectDrawingMatrix.multiply(*transform);
199 state->matrix.loadInverse(roundRectDrawingMatrix);
Chris Craikdeeda3d2014-05-05 19:09:33 -0700200
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
Chris Craikaf4d04c2014-07-29 12:50:14 -0700217 state->innerRect = bounds;
218 state->innerRect.inset(radius);
219 state->radius = radius;
Chris Craikdeeda3d2014-05-05 19:09:33 -0700220
221 // store as immutable so, for this frame, pointer uniquely identifies this bundle of shader info
222 roundRectClipState = state;
223}
224
Chris Craikfca52b752015-04-28 11:45:59 -0700225void 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
Chris Craikdeeda3d2014-05-05 19:09:33 -0700237///////////////////////////////////////////////////////////////////////////////
Romain Guyada4d532012-02-02 17:31:16 -0800238// Queries
239///////////////////////////////////////////////////////////////////////////////
240
241bool Snapshot::isIgnored() const {
242 return invisible || empty;
243}
244
Chris Craik5f803622013-03-21 14:39:04 -0700245void Snapshot::dump() const {
246 ALOGD("Snapshot %p, flags %x, prev %p, height %d, ignored %d, hasComplexClip %d",
Rob Tsuk487a92c2015-01-06 13:22:54 -0800247 this, flags, previous.get(), getViewportHeight(), isIgnored(), !mClipArea->isSimple());
248 const Rect& clipRect(mClipArea->getClipRect());
Chris Craike9c01a42015-04-06 10:47:23 -0700249 ALOGD(" ClipRect %.1f %.1f %.1f %.1f, clip simple %d",
250 clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, mClipArea->isSimple());
251
Chris Craik5f803622013-03-21 14:39:04 -0700252 ALOGD(" Transform (at %p):", transform);
253 transform->dump();
254}
255
Romain Guyada4d532012-02-02 17:31:16 -0800256}; // namespace uirenderer
257}; // namespace android