StatefulBaseRenderer.cpp revision 797b95b26bbb7557678af78b9a2a61830158920f
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(SkMatrix* matrix) const { 105 mSnapshot->transform->copyTo(*matrix); 106} 107 108void StatefulBaseRenderer::translate(float dx, float dy, float dz) { 109 mSnapshot->transform->translate(dx, dy, dz); 110} 111 112void StatefulBaseRenderer::rotate(float degrees) { 113 mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f); 114} 115 116void StatefulBaseRenderer::scale(float sx, float sy) { 117 mSnapshot->transform->scale(sx, sy, 1.0f); 118} 119 120void StatefulBaseRenderer::skew(float sx, float sy) { 121 mSnapshot->transform->skew(sx, sy); 122} 123 124void StatefulBaseRenderer::setMatrix(const SkMatrix* matrix) { 125 if (matrix) { 126 mSnapshot->transform->load(*matrix); 127 } else { 128 mSnapshot->transform->loadIdentity(); 129 } 130} 131 132void StatefulBaseRenderer::setMatrix(const Matrix4& matrix) { 133 mSnapshot->transform->load(matrix); 134} 135 136void StatefulBaseRenderer::concatMatrix(const SkMatrix* matrix) { 137 mat4 transform(*matrix); 138 mSnapshot->transform->multiply(transform); 139} 140 141void StatefulBaseRenderer::concatMatrix(const Matrix4& matrix) { 142 mSnapshot->transform->multiply(matrix); 143} 144 145/////////////////////////////////////////////////////////////////////////////// 146// Clip 147/////////////////////////////////////////////////////////////////////////////// 148 149bool StatefulBaseRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) { 150 if (CC_LIKELY(currentTransform()->rectToRect())) { 151 mDirtyClip |= mSnapshot->clip(left, top, right, bottom, op); 152 return !mSnapshot->clipRect->isEmpty(); 153 } 154 155 SkPath path; 156 path.addRect(left, top, right, bottom); 157 158 return StatefulBaseRenderer::clipPath(&path, op); 159} 160 161bool StatefulBaseRenderer::clipPath(const SkPath* path, SkRegion::Op op) { 162 SkMatrix transform; 163 currentTransform()->copyTo(transform); 164 165 SkPath transformed; 166 path->transform(transform, &transformed); 167 168 SkRegion clip; 169 if (!mSnapshot->previous->clipRegion->isEmpty()) { 170 clip.setRegion(*mSnapshot->previous->clipRegion); 171 } else { 172 if (mSnapshot->previous == firstSnapshot()) { 173 clip.setRect(0, 0, getWidth(), getHeight()); 174 } else { 175 Rect* bounds = mSnapshot->previous->clipRect; 176 clip.setRect(bounds->left, bounds->top, bounds->right, bounds->bottom); 177 } 178 } 179 180 SkRegion region; 181 region.setPath(transformed, clip); 182 183 mDirtyClip |= mSnapshot->clipRegionTransformed(region, op); 184 return !mSnapshot->clipRect->isEmpty(); 185} 186 187bool StatefulBaseRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) { 188 mDirtyClip |= mSnapshot->clipRegionTransformed(*region, op); 189 return !mSnapshot->clipRect->isEmpty(); 190} 191 192void StatefulBaseRenderer::setClippingOutline(LinearAllocator& allocator, const Outline* outline) { 193 mSnapshot->setClippingOutline(allocator, outline); 194} 195 196/////////////////////////////////////////////////////////////////////////////// 197// Quick Rejection 198/////////////////////////////////////////////////////////////////////////////// 199 200/** 201 * Calculates whether content drawn within the passed bounds would be outside of, or intersect with 202 * the clipRect. Does not modify the scissor. 203 * 204 * @param clipRequired if not null, will be set to true if element intersects clip 205 * (and wasn't rejected) 206 * 207 * @param snapOut if set, the geometry will be treated as having an AA ramp. 208 * See Rect::snapGeometryToPixelBoundaries() 209 */ 210bool StatefulBaseRenderer::calculateQuickRejectForScissor(float left, float top, 211 float right, float bottom, 212 bool* clipRequired, bool* roundRectClipRequired, 213 bool snapOut) const { 214 if (mSnapshot->isIgnored() || bottom <= top || right <= left) { 215 return true; 216 } 217 218 Rect r(left, top, right, bottom); 219 currentTransform()->mapRect(r); 220 r.snapGeometryToPixelBoundaries(snapOut); 221 222 Rect clipRect(*currentClipRect()); 223 clipRect.snapToPixelBoundaries(); 224 225 if (!clipRect.intersects(r)) return true; 226 227 // clip is required if geometry intersects clip rect 228 if (clipRequired) { 229 *clipRequired = !clipRect.contains(r); 230 } 231 232 // round rect clip is required if RR clip exists, and geometry intersects its corners 233 if (roundRectClipRequired) { 234 *roundRectClipRequired = mSnapshot->roundRectClipState != NULL 235 && mSnapshot->roundRectClipState->areaRequiresRoundRectClip(r); 236 } 237 return false; 238} 239 240/** 241 * Returns false if drawing won't be clipped out. 242 * 243 * Makes the decision conservatively, by rounding out the mapped rect before comparing with the 244 * clipRect. To be used when perfect, pixel accuracy is not possible (esp. with tessellation) but 245 * rejection is still desired. 246 * 247 * This function, unlike quickRejectSetupScissor, should be used where precise geometry information 248 * isn't known (esp. when geometry adjusts based on scale). Generally, this will be first pass 249 * rejection where precise rejection isn't important, or precise information isn't available. 250 */ 251bool StatefulBaseRenderer::quickRejectConservative(float left, float top, 252 float right, float bottom) const { 253 if (mSnapshot->isIgnored() || bottom <= top || right <= left) { 254 return true; 255 } 256 257 Rect r(left, top, right, bottom); 258 currentTransform()->mapRect(r); 259 r.roundOut(); // rounded out to be conservative 260 261 Rect clipRect(*currentClipRect()); 262 clipRect.snapToPixelBoundaries(); 263 264 if (!clipRect.intersects(r)) return true; 265 266 return false; 267} 268 269}; // namespace uirenderer 270}; // namespace android 271