Home | History | Annotate | Download | only in hwui
      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