1 /* 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 17 #define LOG_TAG "OpenGLRenderer" 18 19 #include "Snapshot.h" 20 21 #include <SkCanvas.h> 22 23 namespace android { 24 namespace uirenderer { 25 26 /////////////////////////////////////////////////////////////////////////////// 27 // Constructors 28 /////////////////////////////////////////////////////////////////////////////// 29 30 Snapshot::Snapshot() 31 : flags(0) 32 , previous(NULL) 33 , layer(NULL) 34 , fbo(0) 35 , invisible(false) 36 , empty(false) 37 , alpha(1.0f) 38 , roundRectClipState(NULL) { 39 transform = &mTransformRoot; 40 clipRect = &mClipRectRoot; 41 region = NULL; 42 clipRegion = &mClipRegionRoot; 43 } 44 45 /** 46 * Copies the specified snapshot/ The specified snapshot is stored as 47 * the previous snapshot. 48 */ 49 Snapshot::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) 56 , alpha(s->alpha) 57 , roundRectClipState(s->roundRectClipState) 58 , mViewportData(s->mViewportData) 59 , mRelativeLightCenter(s->mRelativeLightCenter) { 60 if (saveFlags & SkCanvas::kMatrix_SaveFlag) { 61 mTransformRoot.load(*s->transform); 62 transform = &mTransformRoot; 63 } else { 64 transform = s->transform; 65 } 66 67 if (saveFlags & SkCanvas::kClip_SaveFlag) { 68 mClipRectRoot.set(*s->clipRect); 69 clipRect = &mClipRectRoot; 70 if (!s->clipRegion->isEmpty()) { 71 mClipRegionRoot.op(*s->clipRegion, SkRegion::kUnion_Op); 72 } 73 clipRegion = &mClipRegionRoot; 74 } else { 75 clipRect = s->clipRect; 76 clipRegion = s->clipRegion; 77 } 78 79 if (s->flags & Snapshot::kFlagFboTarget) { 80 flags |= Snapshot::kFlagFboTarget; 81 region = s->region; 82 } else { 83 region = NULL; 84 } 85 } 86 87 /////////////////////////////////////////////////////////////////////////////// 88 // Clipping 89 /////////////////////////////////////////////////////////////////////////////// 90 91 void Snapshot::ensureClipRegion() { 92 if (clipRegion->isEmpty()) { 93 clipRegion->setRect(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom); 94 } 95 } 96 97 void Snapshot::copyClipRectFromRegion() { 98 if (!clipRegion->isEmpty()) { 99 const SkIRect& bounds = clipRegion->getBounds(); 100 clipRect->set(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom); 101 102 if (clipRegion->isRect()) { 103 clipRegion->setEmpty(); 104 } 105 } else { 106 clipRect->setEmpty(); 107 } 108 } 109 110 bool Snapshot::clipRegionOp(float left, float top, float right, float bottom, SkRegion::Op op) { 111 SkIRect tmp; 112 tmp.set(left, top, right, bottom); 113 clipRegion->op(tmp, op); 114 copyClipRectFromRegion(); 115 return true; 116 } 117 118 bool Snapshot::clipRegionTransformed(const SkRegion& region, SkRegion::Op op) { 119 ensureClipRegion(); 120 clipRegion->op(region, op); 121 copyClipRectFromRegion(); 122 flags |= Snapshot::kFlagClipSet; 123 return true; 124 } 125 126 bool Snapshot::clip(float left, float top, float right, float bottom, SkRegion::Op op) { 127 Rect r(left, top, right, bottom); 128 transform->mapRect(r); 129 return clipTransformed(r, op); 130 } 131 132 bool Snapshot::clipTransformed(const Rect& r, SkRegion::Op op) { 133 bool clipped = false; 134 135 switch (op) { 136 case SkRegion::kIntersect_Op: { 137 if (CC_UNLIKELY(!clipRegion->isEmpty())) { 138 ensureClipRegion(); 139 clipped = clipRegionOp(r.left, r.top, r.right, r.bottom, SkRegion::kIntersect_Op); 140 } else { 141 clipped = clipRect->intersect(r); 142 if (!clipped) { 143 clipRect->setEmpty(); 144 clipped = true; 145 } 146 } 147 break; 148 } 149 case SkRegion::kReplace_Op: { 150 setClip(r.left, r.top, r.right, r.bottom); 151 clipped = true; 152 break; 153 } 154 default: { 155 ensureClipRegion(); 156 clipped = clipRegionOp(r.left, r.top, r.right, r.bottom, op); 157 break; 158 } 159 } 160 161 if (clipped) { 162 flags |= Snapshot::kFlagClipSet; 163 } 164 165 return clipped; 166 } 167 168 void Snapshot::setClip(float left, float top, float right, float bottom) { 169 clipRect->set(left, top, right, bottom); 170 if (!clipRegion->isEmpty()) { 171 clipRegion->setEmpty(); 172 } 173 flags |= Snapshot::kFlagClipSet; 174 } 175 176 bool Snapshot::hasPerspectiveTransform() const { 177 return transform->isPerspective(); 178 } 179 180 const Rect& Snapshot::getLocalClip() { 181 mat4 inverse; 182 inverse.loadInverse(*transform); 183 184 mLocalClip.set(*clipRect); 185 inverse.mapRect(mLocalClip); 186 187 return mLocalClip; 188 } 189 190 void Snapshot::resetClip(float left, float top, float right, float bottom) { 191 // TODO: This is incorrect, when we start rendering into a new layer, 192 // we may have to modify the previous snapshot's clip rect and clip 193 // region if the previous restore() call did not restore the clip 194 clipRect = &mClipRectRoot; 195 clipRegion = &mClipRegionRoot; 196 setClip(left, top, right, bottom); 197 } 198 199 /////////////////////////////////////////////////////////////////////////////// 200 // Transforms 201 /////////////////////////////////////////////////////////////////////////////// 202 203 void Snapshot::resetTransform(float x, float y, float z) { 204 // before resetting, map current light pos with inverse of current transform 205 Vector3 center = mRelativeLightCenter; 206 mat4 inverse; 207 inverse.loadInverse(*transform); 208 inverse.mapPoint3d(center); 209 mRelativeLightCenter = center; 210 211 transform = &mTransformRoot; 212 transform->loadTranslate(x, y, z); 213 } 214 215 /////////////////////////////////////////////////////////////////////////////// 216 // Clipping round rect 217 /////////////////////////////////////////////////////////////////////////////// 218 219 void Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds, 220 float radius, bool highPriority) { 221 if (bounds.isEmpty()) { 222 clipRect->setEmpty(); 223 return; 224 } 225 226 if (roundRectClipState && roundRectClipState->highPriority) { 227 // ignore, don't replace, already have a high priority clip 228 return; 229 } 230 231 RoundRectClipState* state = new (allocator) RoundRectClipState; 232 233 state->highPriority = highPriority; 234 235 // store the inverse drawing matrix 236 Matrix4 roundRectDrawingMatrix; 237 roundRectDrawingMatrix.load(getOrthoMatrix()); 238 roundRectDrawingMatrix.multiply(*transform); 239 state->matrix.loadInverse(roundRectDrawingMatrix); 240 241 // compute area under rounded corners - only draws overlapping these rects need to be clipped 242 for (int i = 0 ; i < 4; i++) { 243 state->dangerRects[i] = bounds; 244 } 245 state->dangerRects[0].bottom = state->dangerRects[1].bottom = bounds.top + radius; 246 state->dangerRects[0].right = state->dangerRects[2].right = bounds.left + radius; 247 state->dangerRects[1].left = state->dangerRects[3].left = bounds.right - radius; 248 state->dangerRects[2].top = state->dangerRects[3].top = bounds.bottom - radius; 249 for (int i = 0; i < 4; i++) { 250 transform->mapRect(state->dangerRects[i]); 251 252 // round danger rects out as though they are AA geometry (since they essentially are) 253 state->dangerRects[i].snapGeometryToPixelBoundaries(true); 254 } 255 256 // store RR area 257 state->innerRect = bounds; 258 state->innerRect.inset(radius); 259 state->radius = radius; 260 261 // store as immutable so, for this frame, pointer uniquely identifies this bundle of shader info 262 roundRectClipState = state; 263 } 264 265 /////////////////////////////////////////////////////////////////////////////// 266 // Queries 267 /////////////////////////////////////////////////////////////////////////////// 268 269 bool Snapshot::isIgnored() const { 270 return invisible || empty; 271 } 272 273 void Snapshot::dump() const { 274 ALOGD("Snapshot %p, flags %x, prev %p, height %d, ignored %d, hasComplexClip %d", 275 this, flags, previous.get(), getViewportHeight(), isIgnored(), clipRegion && !clipRegion->isEmpty()); 276 ALOGD(" ClipRect (at %p) %.1f %.1f %.1f %.1f", 277 clipRect, clipRect->left, clipRect->top, clipRect->right, clipRect->bottom); 278 ALOGD(" Transform (at %p):", transform); 279 transform->dump(); 280 } 281 282 }; // namespace uirenderer 283 }; // namespace android 284