Home | History | Annotate | Download | only in hwui
      1 /*
      2  * Copyright (C) 2013 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 #include <SkCanvas.h>
     18 
     19 #include "Debug.h"
     20 #include "DisplayList.h"
     21 #include "DisplayListOp.h"
     22 #include "DisplayListLogBuffer.h"
     23 
     24 namespace android {
     25 namespace uirenderer {
     26 
     27 void DisplayList::outputLogBuffer(int fd) {
     28     DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
     29     if (logBuffer.isEmpty()) {
     30         return;
     31     }
     32 
     33     FILE *file = fdopen(fd, "a");
     34 
     35     fprintf(file, "\nRecent DisplayList operations\n");
     36     logBuffer.outputCommands(file);
     37 
     38     String8 cachesLog;
     39     Caches::getInstance().dumpMemoryUsage(cachesLog);
     40     fprintf(file, "\nCaches:\n%s", cachesLog.string());
     41     fprintf(file, "\n");
     42 
     43     fflush(file);
     44 }
     45 
     46 DisplayList::DisplayList(const DisplayListRenderer& recorder) :
     47     mDestroyed(false), mTransformMatrix(NULL), mTransformCamera(NULL), mTransformMatrix3D(NULL),
     48     mStaticMatrix(NULL), mAnimationMatrix(NULL) {
     49 
     50     initFromDisplayListRenderer(recorder);
     51 }
     52 
     53 DisplayList::~DisplayList() {
     54     mDestroyed = true;
     55     clearResources();
     56 }
     57 
     58 void DisplayList::destroyDisplayListDeferred(DisplayList* displayList) {
     59     if (displayList) {
     60         DISPLAY_LIST_LOGD("Deferring display list destruction");
     61         Caches::getInstance().deleteDisplayListDeferred(displayList);
     62     }
     63 }
     64 
     65 void DisplayList::clearResources() {
     66     mDisplayListData = NULL;
     67 
     68     mClipRectOp = NULL;
     69     mSaveLayerOp = NULL;
     70     mSaveOp = NULL;
     71     mRestoreToCountOp = NULL;
     72 
     73     delete mTransformMatrix;
     74     delete mTransformCamera;
     75     delete mTransformMatrix3D;
     76     delete mStaticMatrix;
     77     delete mAnimationMatrix;
     78 
     79     mTransformMatrix = NULL;
     80     mTransformCamera = NULL;
     81     mTransformMatrix3D = NULL;
     82     mStaticMatrix = NULL;
     83     mAnimationMatrix = NULL;
     84 
     85     Caches& caches = Caches::getInstance();
     86     caches.unregisterFunctors(mFunctorCount);
     87     caches.resourceCache.lock();
     88 
     89     for (size_t i = 0; i < mBitmapResources.size(); i++) {
     90         caches.resourceCache.decrementRefcountLocked(mBitmapResources.itemAt(i));
     91     }
     92 
     93     for (size_t i = 0; i < mOwnedBitmapResources.size(); i++) {
     94         SkBitmap* bitmap = mOwnedBitmapResources.itemAt(i);
     95         caches.resourceCache.decrementRefcountLocked(bitmap);
     96         caches.resourceCache.destructorLocked(bitmap);
     97     }
     98 
     99     for (size_t i = 0; i < mFilterResources.size(); i++) {
    100         caches.resourceCache.decrementRefcountLocked(mFilterResources.itemAt(i));
    101     }
    102 
    103     for (size_t i = 0; i < mPatchResources.size(); i++) {
    104         caches.resourceCache.decrementRefcountLocked(mPatchResources.itemAt(i));
    105     }
    106 
    107     for (size_t i = 0; i < mShaders.size(); i++) {
    108         caches.resourceCache.decrementRefcountLocked(mShaders.itemAt(i));
    109         caches.resourceCache.destructorLocked(mShaders.itemAt(i));
    110     }
    111 
    112     for (size_t i = 0; i < mSourcePaths.size(); i++) {
    113         caches.resourceCache.decrementRefcountLocked(mSourcePaths.itemAt(i));
    114     }
    115 
    116     for (size_t i = 0; i < mLayers.size(); i++) {
    117         caches.resourceCache.decrementRefcountLocked(mLayers.itemAt(i));
    118     }
    119 
    120     caches.resourceCache.unlock();
    121 
    122     for (size_t i = 0; i < mPaints.size(); i++) {
    123         delete mPaints.itemAt(i);
    124     }
    125 
    126     for (size_t i = 0; i < mRegions.size(); i++) {
    127         delete mRegions.itemAt(i);
    128     }
    129 
    130     for (size_t i = 0; i < mPaths.size(); i++) {
    131         delete mPaths.itemAt(i);
    132     }
    133 
    134     for (size_t i = 0; i < mMatrices.size(); i++) {
    135         delete mMatrices.itemAt(i);
    136     }
    137 
    138     mBitmapResources.clear();
    139     mOwnedBitmapResources.clear();
    140     mFilterResources.clear();
    141     mPatchResources.clear();
    142     mShaders.clear();
    143     mSourcePaths.clear();
    144     mPaints.clear();
    145     mRegions.clear();
    146     mPaths.clear();
    147     mMatrices.clear();
    148     mLayers.clear();
    149 }
    150 
    151 void DisplayList::reset() {
    152     clearResources();
    153     init();
    154 }
    155 
    156 void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing) {
    157     if (reusing) {
    158         // re-using display list - clear out previous allocations
    159         clearResources();
    160     }
    161 
    162     init();
    163 
    164     mDisplayListData = recorder.getDisplayListData();
    165     mSize = mDisplayListData->allocator.usedSize();
    166 
    167     if (mSize == 0) {
    168         return;
    169     }
    170 
    171     // allocate reusable ops for state-deferral
    172     LinearAllocator& alloc = mDisplayListData->allocator;
    173     mClipRectOp = new (alloc) ClipRectOp();
    174     mSaveLayerOp = new (alloc) SaveLayerOp();
    175     mSaveOp = new (alloc) SaveOp();
    176     mRestoreToCountOp = new (alloc) RestoreToCountOp();
    177     if (CC_UNLIKELY(!mSaveOp)) { // temporary debug logging
    178         ALOGW("Error: %s's SaveOp not allocated, size %d", getName(), mSize);
    179         CRASH();
    180     }
    181 
    182     mFunctorCount = recorder.getFunctorCount();
    183 
    184     Caches& caches = Caches::getInstance();
    185     caches.registerFunctors(mFunctorCount);
    186     caches.resourceCache.lock();
    187 
    188     const Vector<SkBitmap*>& bitmapResources = recorder.getBitmapResources();
    189     for (size_t i = 0; i < bitmapResources.size(); i++) {
    190         SkBitmap* resource = bitmapResources.itemAt(i);
    191         mBitmapResources.add(resource);
    192         caches.resourceCache.incrementRefcountLocked(resource);
    193     }
    194 
    195     const Vector<SkBitmap*> &ownedBitmapResources = recorder.getOwnedBitmapResources();
    196     for (size_t i = 0; i < ownedBitmapResources.size(); i++) {
    197         SkBitmap* resource = ownedBitmapResources.itemAt(i);
    198         mOwnedBitmapResources.add(resource);
    199         caches.resourceCache.incrementRefcountLocked(resource);
    200     }
    201 
    202     const Vector<SkiaColorFilter*>& filterResources = recorder.getFilterResources();
    203     for (size_t i = 0; i < filterResources.size(); i++) {
    204         SkiaColorFilter* resource = filterResources.itemAt(i);
    205         mFilterResources.add(resource);
    206         caches.resourceCache.incrementRefcountLocked(resource);
    207     }
    208 
    209     const Vector<Res_png_9patch*>& patchResources = recorder.getPatchResources();
    210     for (size_t i = 0; i < patchResources.size(); i++) {
    211         Res_png_9patch* resource = patchResources.itemAt(i);
    212         mPatchResources.add(resource);
    213         caches.resourceCache.incrementRefcountLocked(resource);
    214     }
    215 
    216     const Vector<SkiaShader*>& shaders = recorder.getShaders();
    217     for (size_t i = 0; i < shaders.size(); i++) {
    218         SkiaShader* resource = shaders.itemAt(i);
    219         mShaders.add(resource);
    220         caches.resourceCache.incrementRefcountLocked(resource);
    221     }
    222 
    223     const SortedVector<SkPath*>& sourcePaths = recorder.getSourcePaths();
    224     for (size_t i = 0; i < sourcePaths.size(); i++) {
    225         mSourcePaths.add(sourcePaths.itemAt(i));
    226         caches.resourceCache.incrementRefcountLocked(sourcePaths.itemAt(i));
    227     }
    228 
    229     const Vector<Layer*>& layers = recorder.getLayers();
    230     for (size_t i = 0; i < layers.size(); i++) {
    231         mLayers.add(layers.itemAt(i));
    232         caches.resourceCache.incrementRefcountLocked(layers.itemAt(i));
    233     }
    234 
    235     caches.resourceCache.unlock();
    236 
    237     mPaints.appendVector(recorder.getPaints());
    238     mRegions.appendVector(recorder.getRegions());
    239     mPaths.appendVector(recorder.getPaths());
    240     mMatrices.appendVector(recorder.getMatrices());
    241 }
    242 
    243 void DisplayList::init() {
    244     mSize = 0;
    245     mIsRenderable = true;
    246     mFunctorCount = 0;
    247     mLeft = 0;
    248     mTop = 0;
    249     mRight = 0;
    250     mBottom = 0;
    251     mClipToBounds = true;
    252     mAlpha = 1;
    253     mHasOverlappingRendering = true;
    254     mTranslationX = 0;
    255     mTranslationY = 0;
    256     mRotation = 0;
    257     mRotationX = 0;
    258     mRotationY= 0;
    259     mScaleX = 1;
    260     mScaleY = 1;
    261     mPivotX = 0;
    262     mPivotY = 0;
    263     mCameraDistance = 0;
    264     mMatrixDirty = false;
    265     mMatrixFlags = 0;
    266     mPrevWidth = -1;
    267     mPrevHeight = -1;
    268     mWidth = 0;
    269     mHeight = 0;
    270     mPivotExplicitlySet = false;
    271     mCaching = false;
    272 }
    273 
    274 size_t DisplayList::getSize() {
    275     return mSize;
    276 }
    277 
    278 /**
    279  * This function is a simplified version of replay(), where we simply retrieve and log the
    280  * display list. This function should remain in sync with the replay() function.
    281  */
    282 void DisplayList::output(uint32_t level) {
    283     ALOGD("%*sStart display list (%p, %s, render=%d)", (level - 1) * 2, "", this,
    284             mName.string(), isRenderable());
    285     ALOGD("%*s%s %d", level * 2, "", "Save",
    286             SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
    287 
    288     outputViewProperties(level);
    289     int flags = DisplayListOp::kOpLogFlag_Recurse;
    290     for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
    291         mDisplayListData->displayListOps[i]->output(level, flags);
    292     }
    293 
    294     ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, mName.string());
    295 }
    296 
    297 float DisplayList::getPivotX() {
    298     updateMatrix();
    299     return mPivotX;
    300 }
    301 
    302 float DisplayList::getPivotY() {
    303     updateMatrix();
    304     return mPivotY;
    305 }
    306 
    307 void DisplayList::updateMatrix() {
    308     if (mMatrixDirty) {
    309         if (!mTransformMatrix) {
    310             mTransformMatrix = new SkMatrix();
    311         }
    312         if (mMatrixFlags == 0 || mMatrixFlags == TRANSLATION) {
    313             mTransformMatrix->reset();
    314         } else {
    315             if (!mPivotExplicitlySet) {
    316                 if (mWidth != mPrevWidth || mHeight != mPrevHeight) {
    317                     mPrevWidth = mWidth;
    318                     mPrevHeight = mHeight;
    319                     mPivotX = mPrevWidth / 2.0f;
    320                     mPivotY = mPrevHeight / 2.0f;
    321                 }
    322             }
    323             if ((mMatrixFlags & ROTATION_3D) == 0) {
    324                 mTransformMatrix->setTranslate(mTranslationX, mTranslationY);
    325                 mTransformMatrix->preRotate(mRotation, mPivotX, mPivotY);
    326                 mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY);
    327             } else {
    328                 if (!mTransformCamera) {
    329                     mTransformCamera = new Sk3DView();
    330                     mTransformMatrix3D = new SkMatrix();
    331                 }
    332                 mTransformMatrix->reset();
    333                 mTransformCamera->save();
    334                 mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY);
    335                 mTransformCamera->rotateX(mRotationX);
    336                 mTransformCamera->rotateY(mRotationY);
    337                 mTransformCamera->rotateZ(-mRotation);
    338                 mTransformCamera->getMatrix(mTransformMatrix3D);
    339                 mTransformMatrix3D->preTranslate(-mPivotX, -mPivotY);
    340                 mTransformMatrix3D->postTranslate(mPivotX + mTranslationX,
    341                         mPivotY + mTranslationY);
    342                 mTransformMatrix->postConcat(*mTransformMatrix3D);
    343                 mTransformCamera->restore();
    344             }
    345         }
    346         mMatrixDirty = false;
    347     }
    348 }
    349 
    350 void DisplayList::outputViewProperties(const int level) {
    351     updateMatrix();
    352     if (mLeft != 0 || mTop != 0) {
    353         ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", mLeft, mTop);
    354     }
    355     if (mStaticMatrix) {
    356         ALOGD("%*sConcatMatrix (static) %p: " MATRIX_STRING,
    357                 level * 2, "", mStaticMatrix, MATRIX_ARGS(mStaticMatrix));
    358     }
    359     if (mAnimationMatrix) {
    360         ALOGD("%*sConcatMatrix (animation) %p: " MATRIX_STRING,
    361                 level * 2, "", mAnimationMatrix, MATRIX_ARGS(mAnimationMatrix));
    362     }
    363     if (mMatrixFlags != 0) {
    364         if (mMatrixFlags == TRANSLATION) {
    365             ALOGD("%*sTranslate %f, %f", level * 2, "", mTranslationX, mTranslationY);
    366         } else {
    367             ALOGD("%*sConcatMatrix %p: " MATRIX_STRING,
    368                     level * 2, "", mTransformMatrix, MATRIX_ARGS(mTransformMatrix));
    369         }
    370     }
    371 
    372     bool clipToBoundsNeeded = mCaching ? false : mClipToBounds;
    373     if (mAlpha < 1) {
    374         if (mCaching) {
    375             ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mAlpha);
    376         } else if (!mHasOverlappingRendering) {
    377             ALOGD("%*sScaleAlpha %.2f", level * 2, "", mAlpha);
    378         } else {
    379             int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
    380             if (clipToBoundsNeeded) {
    381                 flags |= SkCanvas::kClipToLayer_SaveFlag;
    382                 clipToBoundsNeeded = false; // clipping done by save layer
    383             }
    384             ALOGD("%*sSaveLayerAlpha %.2f, %.2f, %.2f, %.2f, %d, 0x%x", level * 2, "",
    385                     (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop,
    386                     (int)(mAlpha * 255), flags);
    387         }
    388     }
    389     if (clipToBoundsNeeded) {
    390         ALOGD("%*sClipRect %.2f, %.2f, %.2f, %.2f", level * 2, "", 0.0f, 0.0f,
    391                 (float) mRight - mLeft, (float) mBottom - mTop);
    392     }
    393 }
    394 
    395 /*
    396  * For property operations, we pass a savecount of 0, since the operations aren't part of the
    397  * displaylist, and thus don't have to compensate for the record-time/playback-time discrepancy in
    398  * base saveCount (i.e., how RestoreToCount uses saveCount + mCount)
    399  */
    400 #define PROPERTY_SAVECOUNT 0
    401 
    402 template <class T>
    403 void DisplayList::setViewProperties(OpenGLRenderer& renderer, T& handler,
    404         const int level) {
    405 #if DEBUG_DISPLAY_LIST
    406     outputViewProperties(level);
    407 #endif
    408     updateMatrix();
    409     if (mLeft != 0 || mTop != 0) {
    410         renderer.translate(mLeft, mTop);
    411     }
    412     if (mStaticMatrix) {
    413         renderer.concatMatrix(mStaticMatrix);
    414     } else if (mAnimationMatrix) {
    415         renderer.concatMatrix(mAnimationMatrix);
    416     }
    417     if (mMatrixFlags != 0) {
    418         if (mMatrixFlags == TRANSLATION) {
    419             renderer.translate(mTranslationX, mTranslationY);
    420         } else {
    421             renderer.concatMatrix(mTransformMatrix);
    422         }
    423     }
    424     bool clipToBoundsNeeded = mCaching ? false : mClipToBounds;
    425     if (mAlpha < 1) {
    426         if (mCaching) {
    427             renderer.setOverrideLayerAlpha(mAlpha);
    428         } else if (!mHasOverlappingRendering) {
    429             renderer.scaleAlpha(mAlpha);
    430         } else {
    431             // TODO: should be able to store the size of a DL at record time and not
    432             // have to pass it into this call. In fact, this information might be in the
    433             // location/size info that we store with the new native transform data.
    434             int saveFlags = SkCanvas::kHasAlphaLayer_SaveFlag;
    435             if (clipToBoundsNeeded) {
    436                 saveFlags |= SkCanvas::kClipToLayer_SaveFlag;
    437                 clipToBoundsNeeded = false; // clipping done by saveLayer
    438             }
    439             handler(mSaveLayerOp->reinit(0, 0, mRight - mLeft, mBottom - mTop,
    440                     mAlpha * 255, SkXfermode::kSrcOver_Mode, saveFlags), PROPERTY_SAVECOUNT,
    441                     mClipToBounds);
    442         }
    443     }
    444     if (clipToBoundsNeeded) {
    445         handler(mClipRectOp->reinit(0, 0, mRight - mLeft, mBottom - mTop, SkRegion::kIntersect_Op),
    446                 PROPERTY_SAVECOUNT, mClipToBounds);
    447     }
    448 }
    449 
    450 class DeferOperationHandler {
    451 public:
    452     DeferOperationHandler(DeferStateStruct& deferStruct, int level)
    453         : mDeferStruct(deferStruct), mLevel(level) {}
    454     inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) {
    455         operation->defer(mDeferStruct, saveCount, mLevel, clipToBounds);
    456     }
    457 private:
    458     DeferStateStruct& mDeferStruct;
    459     const int mLevel;
    460 };
    461 
    462 void DisplayList::defer(DeferStateStruct& deferStruct, const int level) {
    463     DeferOperationHandler handler(deferStruct, level);
    464     iterate<DeferOperationHandler>(deferStruct.mRenderer, handler, level);
    465 }
    466 
    467 class ReplayOperationHandler {
    468 public:
    469     ReplayOperationHandler(ReplayStateStruct& replayStruct, int level)
    470         : mReplayStruct(replayStruct), mLevel(level) {}
    471     inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) {
    472 #if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
    473         mReplayStruct.mRenderer.eventMark(operation->name());
    474 #endif
    475         operation->replay(mReplayStruct, saveCount, mLevel, clipToBounds);
    476     }
    477 private:
    478     ReplayStateStruct& mReplayStruct;
    479     const int mLevel;
    480 };
    481 
    482 void DisplayList::replay(ReplayStateStruct& replayStruct, const int level) {
    483     ReplayOperationHandler handler(replayStruct, level);
    484 
    485     replayStruct.mRenderer.startMark(mName.string());
    486     iterate<ReplayOperationHandler>(replayStruct.mRenderer, handler, level);
    487     replayStruct.mRenderer.endMark();
    488 
    489     DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", level * 2, "", this, mName.string(),
    490             replayStruct.mDrawGlStatus);
    491 }
    492 
    493 /**
    494  * This function serves both defer and replay modes, and will organize the displayList's component
    495  * operations for a single frame:
    496  *
    497  * Every 'simple' operation that affects just the matrix and alpha (or other factors of
    498  * DeferredDisplayState) may be issued directly to the renderer, but complex operations (with custom
    499  * defer logic) and operations in displayListOps are issued through the 'handler' which handles the
    500  * defer vs replay logic, per operation
    501  */
    502 template <class T>
    503 void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level) {
    504     if (CC_UNLIKELY(mDestroyed)) { // temporary debug logging
    505         ALOGW("Error: %s is drawing after destruction, size %d", getName(), mSize);
    506         CRASH();
    507     }
    508     if (mSize == 0 || mAlpha <= 0) {
    509         DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, mName.string());
    510         return;
    511     }
    512 
    513 #if DEBUG_DISPLAY_LIST
    514     Rect* clipRect = renderer.getClipRect();
    515     DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.0f, %.0f, %.0f",
    516             level * 2, "", this, mName.string(), clipRect->left, clipRect->top,
    517             clipRect->right, clipRect->bottom);
    518 #endif
    519 
    520     int restoreTo = renderer.getSaveCount();
    521     handler(mSaveOp->reinit(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag),
    522             PROPERTY_SAVECOUNT, mClipToBounds);
    523 
    524     DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "",
    525             SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
    526 
    527     setViewProperties<T>(renderer, handler, level + 1);
    528 
    529     if (mClipToBounds && renderer.quickRejectNoScissor(0, 0, mWidth, mHeight)) {
    530         DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
    531         handler(mRestoreToCountOp->reinit(restoreTo), PROPERTY_SAVECOUNT, mClipToBounds);
    532         renderer.restoreToCount(restoreTo);
    533         renderer.setOverrideLayerAlpha(1.0f);
    534         return;
    535     }
    536 
    537     DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
    538     int saveCount = renderer.getSaveCount() - 1;
    539     for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
    540         DisplayListOp *op = mDisplayListData->displayListOps[i];
    541 
    542 #if DEBUG_DISPLAY_LIST
    543         op->output(level + 1);
    544 #endif
    545 
    546         logBuffer.writeCommand(level, op->name());
    547         handler(op, saveCount, mClipToBounds);
    548     }
    549 
    550     DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
    551     handler(mRestoreToCountOp->reinit(restoreTo), PROPERTY_SAVECOUNT, mClipToBounds);
    552     renderer.restoreToCount(restoreTo);
    553     renderer.setOverrideLayerAlpha(1.0f);
    554 }
    555 
    556 }; // namespace uirenderer
    557 }; // namespace android
    558