Snapshot.cpp revision de89c2fd708d9d7a7e7990e2d6da77c8481a0217
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 23namespace android { 24namespace uirenderer { 25 26/////////////////////////////////////////////////////////////////////////////// 27// Constructors 28/////////////////////////////////////////////////////////////////////////////// 29 30Snapshot::Snapshot() 31 : flags(0) 32 , previous(nullptr) 33 , layer(nullptr) 34 , fbo(0) 35 , invisible(false) 36 , empty(false) 37 , alpha(1.0f) 38 , roundRectClipState(nullptr) 39 , projectionPathMask(nullptr) 40 , mClipArea(&mClipAreaRoot) { 41 transform = &mTransformRoot; 42 region = nullptr; 43 mRelativeLightCenter.x = mRelativeLightCenter.y = mRelativeLightCenter.z = 0; 44} 45 46/** 47 * Copies the specified snapshot/ The specified snapshot is stored as 48 * the previous snapshot. 49 */ 50Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags) 51 : flags(0) 52 , previous(s) 53 , layer(s->layer) 54 , fbo(s->fbo) 55 , invisible(s->invisible) 56 , empty(false) 57 , alpha(s->alpha) 58 , roundRectClipState(s->roundRectClipState) 59 , projectionPathMask(s->projectionPathMask) 60 , mClipArea(nullptr) 61 , mViewportData(s->mViewportData) 62 , mRelativeLightCenter(s->mRelativeLightCenter) { 63 if (saveFlags & SkCanvas::kMatrix_SaveFlag) { 64 mTransformRoot.load(*s->transform); 65 transform = &mTransformRoot; 66 } else { 67 transform = s->transform; 68 } 69 70 if (saveFlags & SkCanvas::kClip_SaveFlag) { 71 mClipAreaRoot = s->getClipArea(); 72 mClipArea = &mClipAreaRoot; 73 } else { 74 mClipArea = s->mClipArea; 75 } 76 77 if (s->flags & Snapshot::kFlagFboTarget) { 78 flags |= Snapshot::kFlagFboTarget; 79 region = s->region; 80 } else { 81 region = nullptr; 82 } 83} 84 85/////////////////////////////////////////////////////////////////////////////// 86// Clipping 87/////////////////////////////////////////////////////////////////////////////// 88 89bool Snapshot::clipRegionTransformed(const SkRegion& region, SkRegion::Op op) { 90 flags |= Snapshot::kFlagClipSet; 91 return mClipArea->clipRegion(region, op); 92} 93 94bool Snapshot::clip(float left, float top, float right, float bottom, SkRegion::Op op) { 95 flags |= Snapshot::kFlagClipSet; 96 return mClipArea->clipRectWithTransform(left, top, right, bottom, transform, op); 97} 98 99bool Snapshot::clipPath(const SkPath& path, SkRegion::Op op) { 100 flags |= Snapshot::kFlagClipSet; 101 return mClipArea->clipPathWithTransform(path, transform, op); 102} 103 104void Snapshot::setClip(float left, float top, float right, float bottom) { 105 mClipArea->setClip(left, top, right, bottom); 106 flags |= Snapshot::kFlagClipSet; 107} 108 109bool Snapshot::hasPerspectiveTransform() const { 110 return transform->isPerspective(); 111} 112 113const Rect& Snapshot::getLocalClip() { 114 mat4 inverse; 115 inverse.loadInverse(*transform); 116 117 mLocalClip.set(mClipArea->getClipRect()); 118 inverse.mapRect(mLocalClip); 119 120 return mLocalClip; 121} 122 123void Snapshot::resetClip(float left, float top, float right, float bottom) { 124 // TODO: This is incorrect, when we start rendering into a new layer, 125 // we may have to modify the previous snapshot's clip rect and clip 126 // region if the previous restore() call did not restore the clip 127 mClipArea = &mClipAreaRoot; 128 setClip(left, top, right, bottom); 129} 130 131/////////////////////////////////////////////////////////////////////////////// 132// Transforms 133/////////////////////////////////////////////////////////////////////////////// 134 135void Snapshot::resetTransform(float x, float y, float z) { 136 // before resetting, map current light pos with inverse of current transform 137 Vector3 center = mRelativeLightCenter; 138 mat4 inverse; 139 inverse.loadInverse(*transform); 140 inverse.mapPoint3d(center); 141 mRelativeLightCenter = center; 142 143 transform = &mTransformRoot; 144 transform->loadTranslate(x, y, z); 145} 146 147void Snapshot::buildScreenSpaceTransform(Matrix4* outTransform) const { 148 // build (reverse ordered) list of the stack of snapshots, terminated with a NULL 149 Vector<const Snapshot*> snapshotList; 150 snapshotList.push(nullptr); 151 const Snapshot* current = this; 152 do { 153 snapshotList.push(current); 154 current = current->previous.get(); 155 } while (current); 156 157 // traverse the list, adding in each transform that contributes to the total transform 158 outTransform->loadIdentity(); 159 for (size_t i = snapshotList.size() - 1; i > 0; i--) { 160 // iterate down the stack 161 const Snapshot* current = snapshotList[i]; 162 const Snapshot* next = snapshotList[i - 1]; 163 if (current->flags & kFlagIsFboLayer) { 164 // if we've hit a layer, translate by the layer's draw offset 165 outTransform->translate(current->layer->layer.left, current->layer->layer.top); 166 } 167 if (!next || (next->flags & kFlagIsFboLayer)) { 168 // if this snapshot is last, or if this snapshot is last before an 169 // FBO layer (which reset the transform), apply it 170 outTransform->multiply(*(current->transform)); 171 } 172 } 173} 174 175/////////////////////////////////////////////////////////////////////////////// 176// Clipping round rect 177/////////////////////////////////////////////////////////////////////////////// 178 179void Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds, 180 float radius, bool highPriority) { 181 if (bounds.isEmpty()) { 182 mClipArea->setEmpty(); 183 return; 184 } 185 186 if (roundRectClipState && roundRectClipState->highPriority) { 187 // ignore, don't replace, already have a high priority clip 188 return; 189 } 190 191 RoundRectClipState* state = new (allocator) RoundRectClipState; 192 193 state->highPriority = highPriority; 194 195 // store the inverse drawing matrix 196 Matrix4 roundRectDrawingMatrix; 197 roundRectDrawingMatrix.load(getOrthoMatrix()); 198 roundRectDrawingMatrix.multiply(*transform); 199 state->matrix.loadInverse(roundRectDrawingMatrix); 200 201 // compute area under rounded corners - only draws overlapping these rects need to be clipped 202 for (int i = 0 ; i < 4; i++) { 203 state->dangerRects[i] = bounds; 204 } 205 state->dangerRects[0].bottom = state->dangerRects[1].bottom = bounds.top + radius; 206 state->dangerRects[0].right = state->dangerRects[2].right = bounds.left + radius; 207 state->dangerRects[1].left = state->dangerRects[3].left = bounds.right - radius; 208 state->dangerRects[2].top = state->dangerRects[3].top = bounds.bottom - radius; 209 for (int i = 0; i < 4; i++) { 210 transform->mapRect(state->dangerRects[i]); 211 212 // round danger rects out as though they are AA geometry (since they essentially are) 213 state->dangerRects[i].snapGeometryToPixelBoundaries(true); 214 } 215 216 // store RR area 217 state->innerRect = bounds; 218 state->innerRect.inset(radius); 219 state->radius = radius; 220 221 // store as immutable so, for this frame, pointer uniquely identifies this bundle of shader info 222 roundRectClipState = state; 223} 224 225void Snapshot::setProjectionPathMask(LinearAllocator& allocator, const SkPath* path) { 226 if (path) { 227 ProjectionPathMask* mask = new (allocator) ProjectionPathMask; 228 mask->projectionMask = path; 229 buildScreenSpaceTransform(&(mask->projectionMaskTransform)); 230 231 projectionPathMask = mask; 232 } else { 233 projectionPathMask = nullptr; 234 } 235} 236 237/////////////////////////////////////////////////////////////////////////////// 238// Queries 239/////////////////////////////////////////////////////////////////////////////// 240 241bool Snapshot::isIgnored() const { 242 return invisible || empty; 243} 244 245void Snapshot::dump() const { 246 ALOGD("Snapshot %p, flags %x, prev %p, height %d, ignored %d, hasComplexClip %d", 247 this, flags, previous.get(), getViewportHeight(), isIgnored(), !mClipArea->isSimple()); 248 const Rect& clipRect(mClipArea->getClipRect()); 249 ALOGD(" ClipRect %.1f %.1f %.1f %.1f, clip simple %d", 250 clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, mClipArea->isSimple()); 251 252 ALOGD(" Transform (at %p):", transform); 253 transform->dump(); 254} 255 256}; // namespace uirenderer 257}; // namespace android 258