blob: beb2e1d0481cc8b1a320a9da4fdf6bde8d543ada [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;
Romain Guyada4d532012-02-02 17:31:16 -080043}
44
45/**
46 * Copies the specified snapshot/ The specified snapshot is stored as
47 * the previous snapshot.
48 */
Chris Craike4aa95e2014-05-08 13:57:05 -070049Snapshot::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)
Chris Craika64a2be2014-05-14 14:17:01 -070056 , alpha(s->alpha)
Chris Craikdeeda3d2014-05-05 19:09:33 -070057 , roundRectClipState(s->roundRectClipState)
Chris Craikfca52b752015-04-28 11:45:59 -070058 , projectionPathMask(s->projectionPathMask)
Rob Tsuk487a92c2015-01-06 13:22:54 -080059 , mClipArea(nullptr)
Chris Craik69e5adf2014-08-14 13:34:01 -070060 , mViewportData(s->mViewportData)
61 , mRelativeLightCenter(s->mRelativeLightCenter) {
Romain Guyada4d532012-02-02 17:31:16 -080062 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) {
Rob Tsuk487a92c2015-01-06 13:22:54 -080070 mClipAreaRoot = s->getClipArea();
71 mClipArea = &mClipAreaRoot;
Romain Guyada4d532012-02-02 17:31:16 -080072 } else {
Rob Tsuk487a92c2015-01-06 13:22:54 -080073 mClipArea = s->mClipArea;
Romain Guyada4d532012-02-02 17:31:16 -080074 }
75
76 if (s->flags & Snapshot::kFlagFboTarget) {
77 flags |= Snapshot::kFlagFboTarget;
78 region = s->region;
79 } else {
Chris Craikd41c4d82015-01-05 15:51:13 -080080 region = nullptr;
Romain Guyada4d532012-02-02 17:31:16 -080081 }
82}
83
84///////////////////////////////////////////////////////////////////////////////
85// Clipping
86///////////////////////////////////////////////////////////////////////////////
87
Romain Guy8ce00302013-01-15 18:51:42 -080088bool Snapshot::clipRegionTransformed(const SkRegion& region, SkRegion::Op op) {
Romain Guy8ce00302013-01-15 18:51:42 -080089 flags |= Snapshot::kFlagClipSet;
Rob Tsuk487a92c2015-01-06 13:22:54 -080090 return mClipArea->clipRegion(region, op);
Romain Guy967e2bf2012-02-07 17:04:34 -080091}
92
Romain Guyada4d532012-02-02 17:31:16 -080093bool Snapshot::clip(float left, float top, float right, float bottom, SkRegion::Op op) {
Rob Tsuk487a92c2015-01-06 13:22:54 -080094 flags |= Snapshot::kFlagClipSet;
95 return mClipArea->clipRectWithTransform(left, top, right, bottom, transform, op);
Romain Guyada4d532012-02-02 17:31:16 -080096}
97
Rob Tsuk487a92c2015-01-06 13:22:54 -080098bool Snapshot::clipPath(const SkPath& path, SkRegion::Op op) {
99 flags |= Snapshot::kFlagClipSet;
100 return mClipArea->clipPathWithTransform(path, transform, op);
Romain Guyada4d532012-02-02 17:31:16 -0800101}
102
103void Snapshot::setClip(float left, float top, float right, float bottom) {
Rob Tsuk487a92c2015-01-06 13:22:54 -0800104 mClipArea->setClip(left, top, right, bottom);
Romain Guyada4d532012-02-02 17:31:16 -0800105 flags |= Snapshot::kFlagClipSet;
106}
107
Romain Guya3dc55f2012-09-28 13:55:44 -0700108bool Snapshot::hasPerspectiveTransform() const {
109 return transform->isPerspective();
110}
111
Romain Guyada4d532012-02-02 17:31:16 -0800112const Rect& Snapshot::getLocalClip() {
113 mat4 inverse;
114 inverse.loadInverse(*transform);
115
Rob Tsuk487a92c2015-01-06 13:22:54 -0800116 mLocalClip.set(mClipArea->getClipRect());
Romain Guyada4d532012-02-02 17:31:16 -0800117 inverse.mapRect(mLocalClip);
118
119 return mLocalClip;
120}
121
122void Snapshot::resetClip(float left, float top, float right, float bottom) {
Romain Guy3bbacf22013-02-06 16:51:04 -0800123 // 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
Rob Tsuk487a92c2015-01-06 13:22:54 -0800126 mClipArea = &mClipAreaRoot;
Romain Guy967e2bf2012-02-07 17:04:34 -0800127 setClip(left, top, right, bottom);
Romain Guyada4d532012-02-02 17:31:16 -0800128}
129
130///////////////////////////////////////////////////////////////////////////////
131// Transforms
132///////////////////////////////////////////////////////////////////////////////
133
134void Snapshot::resetTransform(float x, float y, float z) {
Chris Craik69e5adf2014-08-14 13:34:01 -0700135 // 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
Romain Guyada4d532012-02-02 17:31:16 -0800142 transform = &mTransformRoot;
143 transform->loadTranslate(x, y, z);
144}
145
Chris Craikfca52b752015-04-28 11:45:59 -0700146void 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
Romain Guyada4d532012-02-02 17:31:16 -0800174///////////////////////////////////////////////////////////////////////////////
Chris Craikaf4d04c2014-07-29 12:50:14 -0700175// Clipping round rect
Chris Craikdeeda3d2014-05-05 19:09:33 -0700176///////////////////////////////////////////////////////////////////////////////
177
Chris Craike83cbd42014-09-03 17:52:24 -0700178void Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds,
179 float radius, bool highPriority) {
Chris Craikaf4d04c2014-07-29 12:50:14 -0700180 if (bounds.isEmpty()) {
Rob Tsuk487a92c2015-01-06 13:22:54 -0800181 mClipArea->setEmpty();
Chris Craikaf4d04c2014-07-29 12:50:14 -0700182 return;
183 }
Chris Craikdeeda3d2014-05-05 19:09:33 -0700184
Chris Craike83cbd42014-09-03 17:52:24 -0700185 if (roundRectClipState && roundRectClipState->highPriority) {
186 // ignore, don't replace, already have a high priority clip
187 return;
188 }
189
Chris Craikdeeda3d2014-05-05 19:09:33 -0700190 RoundRectClipState* state = new (allocator) RoundRectClipState;
191
Chris Craike83cbd42014-09-03 17:52:24 -0700192 state->highPriority = highPriority;
193
Chris Craikdeeda3d2014-05-05 19:09:33 -0700194 // store the inverse drawing matrix
Chris Craikaf4d04c2014-07-29 12:50:14 -0700195 Matrix4 roundRectDrawingMatrix;
196 roundRectDrawingMatrix.load(getOrthoMatrix());
197 roundRectDrawingMatrix.multiply(*transform);
198 state->matrix.loadInverse(roundRectDrawingMatrix);
Chris Craikdeeda3d2014-05-05 19:09:33 -0700199
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
Chris Craikaf4d04c2014-07-29 12:50:14 -0700216 state->innerRect = bounds;
217 state->innerRect.inset(radius);
218 state->radius = radius;
Chris Craikdeeda3d2014-05-05 19:09:33 -0700219
220 // store as immutable so, for this frame, pointer uniquely identifies this bundle of shader info
221 roundRectClipState = state;
222}
223
Chris Craikfca52b752015-04-28 11:45:59 -0700224void 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
Chris Craikdeeda3d2014-05-05 19:09:33 -0700236///////////////////////////////////////////////////////////////////////////////
Romain Guyada4d532012-02-02 17:31:16 -0800237// Queries
238///////////////////////////////////////////////////////////////////////////////
239
240bool Snapshot::isIgnored() const {
241 return invisible || empty;
242}
243
Chris Craik5f803622013-03-21 14:39:04 -0700244void Snapshot::dump() const {
245 ALOGD("Snapshot %p, flags %x, prev %p, height %d, ignored %d, hasComplexClip %d",
Rob Tsuk487a92c2015-01-06 13:22:54 -0800246 this, flags, previous.get(), getViewportHeight(), isIgnored(), !mClipArea->isSimple());
247 const Rect& clipRect(mClipArea->getClipRect());
Chris Craike9c01a42015-04-06 10:47:23 -0700248 ALOGD(" ClipRect %.1f %.1f %.1f %.1f, clip simple %d",
249 clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, mClipArea->isSimple());
250
Chris Craik5f803622013-03-21 14:39:04 -0700251 ALOGD(" Transform (at %p):", transform);
252 transform->dump();
253}
254
Romain Guyada4d532012-02-02 17:31:16 -0800255}; // namespace uirenderer
256}; // namespace android