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