blob: 473005cf2c939458eeaee56ead16a474c5822030 [file] [log] [blame]
Chris Craik14e51302013-12-30 15:32:54 -08001/*
2 * Copyright (C) 2014 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 Craikdeeda3d2014-05-05 19:09:33 -070017#define LOG_TAG "OpenGLRenderer"
18
Chris Craik14e51302013-12-30 15:32:54 -080019#include <SkCanvas.h>
20
21#include "StatefulBaseRenderer.h"
22
23namespace android {
24namespace uirenderer {
25
Chris Craik058fc642014-07-23 18:19:28 -070026StatefulBaseRenderer::StatefulBaseRenderer()
27 : mDirtyClip(false)
28 , mWidth(-1)
29 , mHeight(-1)
30 , mSaveCount(1)
31 , mFirstSnapshot(new Snapshot)
32 , mSnapshot(mFirstSnapshot) {
Chris Craik14e51302013-12-30 15:32:54 -080033}
34
35void StatefulBaseRenderer::initializeSaveStack(float clipLeft, float clipTop,
36 float clipRight, float clipBottom) {
37 mSnapshot = new Snapshot(mFirstSnapshot,
38 SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
39 mSnapshot->setClip(clipLeft, clipTop, clipRight, clipBottom);
40 mSnapshot->fbo = getTargetFbo();
41 mSaveCount = 1;
42}
43
Chris Craik797b95b2014-05-20 18:10:25 -070044void StatefulBaseRenderer::setViewport(int width, int height) {
Chris Craik14e51302013-12-30 15:32:54 -080045 mWidth = width;
46 mHeight = height;
Chris Craika64a2be2014-05-14 14:17:01 -070047 mFirstSnapshot->initializeViewport(width, height);
Chris Craik797b95b2014-05-20 18:10:25 -070048 onViewportInitialized();
49}
50
Chris Craik14e51302013-12-30 15:32:54 -080051///////////////////////////////////////////////////////////////////////////////
52// Save (layer)
53///////////////////////////////////////////////////////////////////////////////
54
55/**
56 * Non-virtual implementation of save, guaranteed to save without side-effects
57 *
58 * The approach here and in restoreSnapshot(), allows subclasses to directly manipulate the save
59 * stack, and ensures restoreToCount() doesn't call back into subclass overrides.
60 */
61int StatefulBaseRenderer::saveSnapshot(int flags) {
62 mSnapshot = new Snapshot(mSnapshot, flags);
63 return mSaveCount++;
64}
65
66int StatefulBaseRenderer::save(int flags) {
67 return saveSnapshot(flags);
68}
69
70/**
71 * Non-virtual implementation of restore, guaranteed to restore without side-effects.
72 */
73void StatefulBaseRenderer::restoreSnapshot() {
74 sp<Snapshot> toRemove = mSnapshot;
75 sp<Snapshot> toRestore = mSnapshot->previous;
76
77 mSaveCount--;
78 mSnapshot = toRestore;
79
80 // subclass handles restore implementation
81 onSnapshotRestored(*toRemove, *toRestore);
82}
83
84void StatefulBaseRenderer::restore() {
85 if (mSaveCount > 1) {
86 restoreSnapshot();
87 }
88}
89
90void StatefulBaseRenderer::restoreToCount(int saveCount) {
91 if (saveCount < 1) saveCount = 1;
92
93 while (mSaveCount > saveCount) {
94 restoreSnapshot();
95 }
96}
97
98///////////////////////////////////////////////////////////////////////////////
99// Matrix
100///////////////////////////////////////////////////////////////////////////////
101
Chris Craik05f3d6e2014-06-02 16:27:04 -0700102void StatefulBaseRenderer::getMatrix(Matrix4* matrix) const {
103 matrix->load(*(mSnapshot->transform));
104}
105
Chris Craik14e51302013-12-30 15:32:54 -0800106void StatefulBaseRenderer::getMatrix(SkMatrix* matrix) const {
107 mSnapshot->transform->copyTo(*matrix);
108}
109
110void StatefulBaseRenderer::translate(float dx, float dy, float dz) {
111 mSnapshot->transform->translate(dx, dy, dz);
112}
113
114void StatefulBaseRenderer::rotate(float degrees) {
115 mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f);
116}
117
118void StatefulBaseRenderer::scale(float sx, float sy) {
119 mSnapshot->transform->scale(sx, sy, 1.0f);
120}
121
122void StatefulBaseRenderer::skew(float sx, float sy) {
123 mSnapshot->transform->skew(sx, sy);
124}
125
Derek Sollenberger13908822013-12-10 12:28:58 -0500126void StatefulBaseRenderer::setMatrix(const SkMatrix& matrix) {
127 mSnapshot->transform->load(matrix);
Chris Craik14e51302013-12-30 15:32:54 -0800128}
129
130void StatefulBaseRenderer::setMatrix(const Matrix4& matrix) {
131 mSnapshot->transform->load(matrix);
132}
133
Derek Sollenberger13908822013-12-10 12:28:58 -0500134void StatefulBaseRenderer::concatMatrix(const SkMatrix& matrix) {
135 mat4 transform(matrix);
Chris Craik14e51302013-12-30 15:32:54 -0800136 mSnapshot->transform->multiply(transform);
137}
138
139void StatefulBaseRenderer::concatMatrix(const Matrix4& matrix) {
140 mSnapshot->transform->multiply(matrix);
141}
142
143///////////////////////////////////////////////////////////////////////////////
144// Clip
145///////////////////////////////////////////////////////////////////////////////
146
Chris Craikd6b65f62014-01-01 14:45:21 -0800147bool StatefulBaseRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
148 if (CC_LIKELY(currentTransform()->rectToRect())) {
149 mDirtyClip |= mSnapshot->clip(left, top, right, bottom, op);
150 return !mSnapshot->clipRect->isEmpty();
151 }
152
153 SkPath path;
154 path.addRect(left, top, right, bottom);
155
156 return StatefulBaseRenderer::clipPath(&path, op);
157}
158
Chris Craikd218a922014-01-02 17:13:34 -0800159bool StatefulBaseRenderer::clipPath(const SkPath* path, SkRegion::Op op) {
Chris Craikd6b65f62014-01-01 14:45:21 -0800160 SkMatrix transform;
161 currentTransform()->copyTo(transform);
162
163 SkPath transformed;
164 path->transform(transform, &transformed);
165
166 SkRegion clip;
167 if (!mSnapshot->previous->clipRegion->isEmpty()) {
168 clip.setRegion(*mSnapshot->previous->clipRegion);
169 } else {
170 if (mSnapshot->previous == firstSnapshot()) {
171 clip.setRect(0, 0, getWidth(), getHeight());
172 } else {
173 Rect* bounds = mSnapshot->previous->clipRect;
174 clip.setRect(bounds->left, bounds->top, bounds->right, bounds->bottom);
175 }
176 }
177
178 SkRegion region;
179 region.setPath(transformed, clip);
180
Chris Craik62d307c2014-07-29 10:35:13 -0700181 // region is the transformed input path, masked by the previous clip
Chris Craikd6b65f62014-01-01 14:45:21 -0800182 mDirtyClip |= mSnapshot->clipRegionTransformed(region, op);
183 return !mSnapshot->clipRect->isEmpty();
184}
185
Chris Craikd218a922014-01-02 17:13:34 -0800186bool StatefulBaseRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) {
Chris Craikd6b65f62014-01-01 14:45:21 -0800187 mDirtyClip |= mSnapshot->clipRegionTransformed(*region, op);
188 return !mSnapshot->clipRect->isEmpty();
189}
Chris Craik14e51302013-12-30 15:32:54 -0800190
Chris Craikdeeda3d2014-05-05 19:09:33 -0700191void StatefulBaseRenderer::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
192 mSnapshot->setClippingOutline(allocator, outline);
193}
194
Chris Craik14e51302013-12-30 15:32:54 -0800195///////////////////////////////////////////////////////////////////////////////
196// Quick Rejection
197///////////////////////////////////////////////////////////////////////////////
198
199/**
200 * Calculates whether content drawn within the passed bounds would be outside of, or intersect with
201 * the clipRect. Does not modify the scissor.
202 *
203 * @param clipRequired if not null, will be set to true if element intersects clip
204 * (and wasn't rejected)
205 *
206 * @param snapOut if set, the geometry will be treated as having an AA ramp.
207 * See Rect::snapGeometryToPixelBoundaries()
208 */
209bool StatefulBaseRenderer::calculateQuickRejectForScissor(float left, float top,
Chris Craikdeeda3d2014-05-05 19:09:33 -0700210 float right, float bottom,
211 bool* clipRequired, bool* roundRectClipRequired,
212 bool snapOut) const {
Chris Craik14e51302013-12-30 15:32:54 -0800213 if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
214 return true;
215 }
216
217 Rect r(left, top, right, bottom);
Chris Craikd6b65f62014-01-01 14:45:21 -0800218 currentTransform()->mapRect(r);
Chris Craik14e51302013-12-30 15:32:54 -0800219 r.snapGeometryToPixelBoundaries(snapOut);
220
Chris Craikd6b65f62014-01-01 14:45:21 -0800221 Rect clipRect(*currentClipRect());
Chris Craik14e51302013-12-30 15:32:54 -0800222 clipRect.snapToPixelBoundaries();
223
224 if (!clipRect.intersects(r)) return true;
225
226 // clip is required if geometry intersects clip rect
Chris Craikdeeda3d2014-05-05 19:09:33 -0700227 if (clipRequired) {
228 *clipRequired = !clipRect.contains(r);
229 }
230
231 // round rect clip is required if RR clip exists, and geometry intersects its corners
232 if (roundRectClipRequired) {
233 *roundRectClipRequired = mSnapshot->roundRectClipState != NULL
234 && mSnapshot->roundRectClipState->areaRequiresRoundRectClip(r);
235 }
Chris Craik14e51302013-12-30 15:32:54 -0800236 return false;
237}
238
239/**
240 * Returns false if drawing won't be clipped out.
241 *
242 * Makes the decision conservatively, by rounding out the mapped rect before comparing with the
243 * clipRect. To be used when perfect, pixel accuracy is not possible (esp. with tessellation) but
244 * rejection is still desired.
245 *
246 * This function, unlike quickRejectSetupScissor, should be used where precise geometry information
247 * isn't known (esp. when geometry adjusts based on scale). Generally, this will be first pass
248 * rejection where precise rejection isn't important, or precise information isn't available.
249 */
250bool StatefulBaseRenderer::quickRejectConservative(float left, float top,
251 float right, float bottom) const {
252 if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
253 return true;
254 }
255
256 Rect r(left, top, right, bottom);
Chris Craikd6b65f62014-01-01 14:45:21 -0800257 currentTransform()->mapRect(r);
Chris Craik14e51302013-12-30 15:32:54 -0800258 r.roundOut(); // rounded out to be conservative
259
Chris Craikd6b65f62014-01-01 14:45:21 -0800260 Rect clipRect(*currentClipRect());
Chris Craik14e51302013-12-30 15:32:54 -0800261 clipRect.snapToPixelBoundaries();
262
263 if (!clipRect.intersects(r)) return true;
264
265 return false;
266}
267
268}; // namespace uirenderer
269}; // namespace android