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