StatefulBaseRenderer.cpp revision 05f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5
1/* 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 17#define LOG_TAG "OpenGLRenderer" 18 19#include <SkCanvas.h> 20 21#include "StatefulBaseRenderer.h" 22 23namespace android { 24namespace uirenderer { 25 26StatefulBaseRenderer::StatefulBaseRenderer() : 27 mDirtyClip(false), mWidth(-1), mHeight(-1), 28 mSaveCount(1), mFirstSnapshot(new Snapshot), mSnapshot(mFirstSnapshot), 29 mLightCenter(FLT_MIN, FLT_MIN, FLT_MIN), mLightRadius(FLT_MIN) { 30} 31 32void StatefulBaseRenderer::initializeSaveStack(float clipLeft, float clipTop, 33 float clipRight, float clipBottom) { 34 mSnapshot = new Snapshot(mFirstSnapshot, 35 SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); 36 mSnapshot->setClip(clipLeft, clipTop, clipRight, clipBottom); 37 mSnapshot->fbo = getTargetFbo(); 38 mSaveCount = 1; 39} 40 41void StatefulBaseRenderer::setViewport(int width, int height) { 42 mWidth = width; 43 mHeight = height; 44 mFirstSnapshot->initializeViewport(width, height); 45 onViewportInitialized(); 46} 47 48void StatefulBaseRenderer::initializeLight(const Vector3& lightCenter, float lightRadius) { 49 mLightCenter = lightCenter; 50 mLightRadius = lightRadius; 51} 52 53/////////////////////////////////////////////////////////////////////////////// 54// Save (layer) 55/////////////////////////////////////////////////////////////////////////////// 56 57/** 58 * Non-virtual implementation of save, guaranteed to save without side-effects 59 * 60 * The approach here and in restoreSnapshot(), allows subclasses to directly manipulate the save 61 * stack, and ensures restoreToCount() doesn't call back into subclass overrides. 62 */ 63int StatefulBaseRenderer::saveSnapshot(int flags) { 64 mSnapshot = new Snapshot(mSnapshot, flags); 65 return mSaveCount++; 66} 67 68int StatefulBaseRenderer::save(int flags) { 69 return saveSnapshot(flags); 70} 71 72/** 73 * Non-virtual implementation of restore, guaranteed to restore without side-effects. 74 */ 75void StatefulBaseRenderer::restoreSnapshot() { 76 sp<Snapshot> toRemove = mSnapshot; 77 sp<Snapshot> toRestore = mSnapshot->previous; 78 79 mSaveCount--; 80 mSnapshot = toRestore; 81 82 // subclass handles restore implementation 83 onSnapshotRestored(*toRemove, *toRestore); 84} 85 86void StatefulBaseRenderer::restore() { 87 if (mSaveCount > 1) { 88 restoreSnapshot(); 89 } 90} 91 92void StatefulBaseRenderer::restoreToCount(int saveCount) { 93 if (saveCount < 1) saveCount = 1; 94 95 while (mSaveCount > saveCount) { 96 restoreSnapshot(); 97 } 98} 99 100/////////////////////////////////////////////////////////////////////////////// 101// Matrix 102/////////////////////////////////////////////////////////////////////////////// 103 104void StatefulBaseRenderer::getMatrix(Matrix4* matrix) const { 105 matrix->load(*(mSnapshot->transform)); 106} 107 108void StatefulBaseRenderer::getMatrix(SkMatrix* matrix) const { 109 mSnapshot->transform->copyTo(*matrix); 110} 111 112void StatefulBaseRenderer::translate(float dx, float dy, float dz) { 113 mSnapshot->transform->translate(dx, dy, dz); 114} 115 116void StatefulBaseRenderer::rotate(float degrees) { 117 mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f); 118} 119 120void StatefulBaseRenderer::scale(float sx, float sy) { 121 mSnapshot->transform->scale(sx, sy, 1.0f); 122} 123 124void StatefulBaseRenderer::skew(float sx, float sy) { 125 mSnapshot->transform->skew(sx, sy); 126} 127 128void StatefulBaseRenderer::setMatrix(const SkMatrix* matrix) { 129 if (matrix) { 130 mSnapshot->transform->load(*matrix); 131 } else { 132 mSnapshot->transform->loadIdentity(); 133 } 134} 135 136void StatefulBaseRenderer::setMatrix(const Matrix4& matrix) { 137 mSnapshot->transform->load(matrix); 138} 139 140void StatefulBaseRenderer::concatMatrix(const SkMatrix* matrix) { 141 mat4 transform(*matrix); 142 mSnapshot->transform->multiply(transform); 143} 144 145void StatefulBaseRenderer::concatMatrix(const Matrix4& matrix) { 146 mSnapshot->transform->multiply(matrix); 147} 148 149/////////////////////////////////////////////////////////////////////////////// 150// Clip 151/////////////////////////////////////////////////////////////////////////////// 152 153bool StatefulBaseRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) { 154 if (CC_LIKELY(currentTransform()->rectToRect())) { 155 mDirtyClip |= mSnapshot->clip(left, top, right, bottom, op); 156 return !mSnapshot->clipRect->isEmpty(); 157 } 158 159 SkPath path; 160 path.addRect(left, top, right, bottom); 161 162 return StatefulBaseRenderer::clipPath(&path, op); 163} 164 165bool StatefulBaseRenderer::clipPath(const SkPath* path, SkRegion::Op op) { 166 SkMatrix transform; 167 currentTransform()->copyTo(transform); 168 169 SkPath transformed; 170 path->transform(transform, &transformed); 171 172 SkRegion clip; 173 if (!mSnapshot->previous->clipRegion->isEmpty()) { 174 clip.setRegion(*mSnapshot->previous->clipRegion); 175 } else { 176 if (mSnapshot->previous == firstSnapshot()) { 177 clip.setRect(0, 0, getWidth(), getHeight()); 178 } else { 179 Rect* bounds = mSnapshot->previous->clipRect; 180 clip.setRect(bounds->left, bounds->top, bounds->right, bounds->bottom); 181 } 182 } 183 184 SkRegion region; 185 region.setPath(transformed, clip); 186 187 mDirtyClip |= mSnapshot->clipRegionTransformed(region, op); 188 return !mSnapshot->clipRect->isEmpty(); 189} 190 191bool StatefulBaseRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) { 192 mDirtyClip |= mSnapshot->clipRegionTransformed(*region, op); 193 return !mSnapshot->clipRect->isEmpty(); 194} 195 196void StatefulBaseRenderer::setClippingOutline(LinearAllocator& allocator, const Outline* outline) { 197 mSnapshot->setClippingOutline(allocator, outline); 198} 199 200/////////////////////////////////////////////////////////////////////////////// 201// Quick Rejection 202/////////////////////////////////////////////////////////////////////////////// 203 204/** 205 * Calculates whether content drawn within the passed bounds would be outside of, or intersect with 206 * the clipRect. Does not modify the scissor. 207 * 208 * @param clipRequired if not null, will be set to true if element intersects clip 209 * (and wasn't rejected) 210 * 211 * @param snapOut if set, the geometry will be treated as having an AA ramp. 212 * See Rect::snapGeometryToPixelBoundaries() 213 */ 214bool StatefulBaseRenderer::calculateQuickRejectForScissor(float left, float top, 215 float right, float bottom, 216 bool* clipRequired, bool* roundRectClipRequired, 217 bool snapOut) const { 218 if (mSnapshot->isIgnored() || bottom <= top || right <= left) { 219 return true; 220 } 221 222 Rect r(left, top, right, bottom); 223 currentTransform()->mapRect(r); 224 r.snapGeometryToPixelBoundaries(snapOut); 225 226 Rect clipRect(*currentClipRect()); 227 clipRect.snapToPixelBoundaries(); 228 229 if (!clipRect.intersects(r)) return true; 230 231 // clip is required if geometry intersects clip rect 232 if (clipRequired) { 233 *clipRequired = !clipRect.contains(r); 234 } 235 236 // round rect clip is required if RR clip exists, and geometry intersects its corners 237 if (roundRectClipRequired) { 238 *roundRectClipRequired = mSnapshot->roundRectClipState != NULL 239 && mSnapshot->roundRectClipState->areaRequiresRoundRectClip(r); 240 } 241 return false; 242} 243 244/** 245 * Returns false if drawing won't be clipped out. 246 * 247 * Makes the decision conservatively, by rounding out the mapped rect before comparing with the 248 * clipRect. To be used when perfect, pixel accuracy is not possible (esp. with tessellation) but 249 * rejection is still desired. 250 * 251 * This function, unlike quickRejectSetupScissor, should be used where precise geometry information 252 * isn't known (esp. when geometry adjusts based on scale). Generally, this will be first pass 253 * rejection where precise rejection isn't important, or precise information isn't available. 254 */ 255bool StatefulBaseRenderer::quickRejectConservative(float left, float top, 256 float right, float bottom) const { 257 if (mSnapshot->isIgnored() || bottom <= top || right <= left) { 258 return true; 259 } 260 261 Rect r(left, top, right, bottom); 262 currentTransform()->mapRect(r); 263 r.roundOut(); // rounded out to be conservative 264 265 Rect clipRect(*currentClipRect()); 266 clipRect.snapToPixelBoundaries(); 267 268 if (!clipRect.intersects(r)) return true; 269 270 return false; 271} 272 273}; // namespace uirenderer 274}; // namespace android 275