DisplayList.cpp revision eea6ef9c767c734797912022113191dd255c4ae6
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#define ATRACE_TAG ATRACE_TAG_VIEW
18
19#include <SkCanvas.h>
20#include <algorithm>
21
22#include <utils/Trace.h>
23
24#include "Debug.h"
25#include "DisplayList.h"
26#include "DisplayListOp.h"
27#include "DisplayListLogBuffer.h"
28
29namespace android {
30namespace uirenderer {
31
32void DisplayList::outputLogBuffer(int fd) {
33    DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
34    if (logBuffer.isEmpty()) {
35        return;
36    }
37
38    FILE *file = fdopen(fd, "a");
39
40    fprintf(file, "\nRecent DisplayList operations\n");
41    logBuffer.outputCommands(file);
42
43    String8 cachesLog;
44    Caches::getInstance().dumpMemoryUsage(cachesLog);
45    fprintf(file, "\nCaches:\n%s", cachesLog.string());
46    fprintf(file, "\n");
47
48    fflush(file);
49}
50
51DisplayList::DisplayList() :
52        mDisplayListData(0), mDestroyed(false), mTransformMatrix(NULL), mTransformCamera(NULL),
53        mTransformMatrix3D(NULL), mStaticMatrix(NULL), mAnimationMatrix(NULL) {
54
55    mLeft = 0;
56    mTop = 0;
57    mRight = 0;
58    mBottom = 0;
59    mClipToBounds = true;
60    mIsolatedZVolume = true;
61    mProjectBackwards = false;
62    mProjectionReceiver = false;
63    mOutline.rewind();
64    mClipToOutline = false;
65    mCastsShadow = false;
66    mUsesGlobalCamera = false;
67    mAlpha = 1;
68    mHasOverlappingRendering = true;
69    mTranslationX = 0;
70    mTranslationY = 0;
71    mTranslationZ = 0;
72    mRotation = 0;
73    mRotationX = 0;
74    mRotationY= 0;
75    mScaleX = 1;
76    mScaleY = 1;
77    mPivotX = 0;
78    mPivotY = 0;
79    mCameraDistance = 0;
80    mMatrixDirty = false;
81    mMatrixFlags = 0;
82    mPrevWidth = -1;
83    mPrevHeight = -1;
84    mWidth = 0;
85    mHeight = 0;
86    mPivotExplicitlySet = false;
87    mCaching = false;
88}
89
90DisplayList::~DisplayList() {
91    LOG_ALWAYS_FATAL_IF(mDestroyed, "Double destroyed DisplayList %p", this);
92
93    mDestroyed = true;
94    delete mDisplayListData;
95    delete mTransformMatrix;
96    delete mTransformCamera;
97    delete mTransformMatrix3D;
98    delete mStaticMatrix;
99    delete mAnimationMatrix;
100}
101
102void DisplayList::destroyDisplayListDeferred(DisplayList* displayList) {
103    if (displayList) {
104        DISPLAY_LIST_LOGD("Deferring display list destruction");
105        Caches::getInstance().deleteDisplayListDeferred(displayList);
106    }
107}
108
109void DisplayList::setData(DisplayListData* data) {
110    delete mDisplayListData;
111    mDisplayListData = data;
112}
113
114/**
115 * This function is a simplified version of replay(), where we simply retrieve and log the
116 * display list. This function should remain in sync with the replay() function.
117 */
118void DisplayList::output(uint32_t level) {
119    ALOGD("%*sStart display list (%p, %s, render=%d)", (level - 1) * 2, "", this,
120            mName.string(), isRenderable());
121    ALOGD("%*s%s %d", level * 2, "", "Save",
122            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
123
124    outputViewProperties(level);
125    int flags = DisplayListOp::kOpLogFlag_Recurse;
126    for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
127        mDisplayListData->displayListOps[i]->output(level, flags);
128    }
129
130    ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, mName.string());
131}
132
133float DisplayList::getPivotX() {
134    updateMatrix();
135    return mPivotX;
136}
137
138float DisplayList::getPivotY() {
139    updateMatrix();
140    return mPivotY;
141}
142
143void DisplayList::updateMatrix() {
144    if (mMatrixDirty) {
145        // NOTE: mTransformMatrix won't be up to date if a DisplayList goes from a complex transform
146        // to a pure translate. This is safe because the matrix isn't read in pure translate cases.
147        if (mMatrixFlags && mMatrixFlags != TRANSLATION) {
148            if (!mTransformMatrix) {
149                // only allocate a matrix if we have a complex transform
150                mTransformMatrix = new Matrix4();
151            }
152            if (!mPivotExplicitlySet) {
153                if (mWidth != mPrevWidth || mHeight != mPrevHeight) {
154                    mPrevWidth = mWidth;
155                    mPrevHeight = mHeight;
156                    mPivotX = mPrevWidth / 2.0f;
157                    mPivotY = mPrevHeight / 2.0f;
158                }
159            }
160            const bool perspectiveEnabled = Caches::getInstance().propertyEnable3d;
161            if (!perspectiveEnabled && (mMatrixFlags & ROTATION_3D) == 0) {
162                mTransformMatrix->loadTranslate(
163                        mPivotX + mTranslationX,
164                        mPivotY + mTranslationY,
165                        0);
166                mTransformMatrix->rotate(mRotation, 0, 0, 1);
167                mTransformMatrix->scale(mScaleX, mScaleY, 1);
168                mTransformMatrix->translate(-mPivotX, -mPivotY);
169            } else {
170                if (perspectiveEnabled) {
171                    mTransformMatrix->loadTranslate(
172                            mPivotX + mTranslationX,
173                            mPivotY + mTranslationY,
174                            mTranslationZ);
175                    mTransformMatrix->rotate(mRotationX, 1, 0, 0);
176                    mTransformMatrix->rotate(mRotationY, 0, 1, 0);
177                    mTransformMatrix->rotate(mRotation, 0, 0, 1);
178                    mTransformMatrix->scale(mScaleX, mScaleY, 1);
179                    mTransformMatrix->translate(-mPivotX, -mPivotY);
180                } else {
181                    /* TODO: support this old transform approach, based on API level */
182                    if (!mTransformCamera) {
183                        mTransformCamera = new Sk3DView();
184                        mTransformMatrix3D = new SkMatrix();
185                    }
186                    SkMatrix transformMatrix;
187                    transformMatrix.reset();
188                    mTransformCamera->save();
189                    transformMatrix.preScale(mScaleX, mScaleY, mPivotX, mPivotY);
190                    mTransformCamera->rotateX(mRotationX);
191                    mTransformCamera->rotateY(mRotationY);
192                    mTransformCamera->rotateZ(-mRotation);
193                    mTransformCamera->getMatrix(mTransformMatrix3D);
194                    mTransformMatrix3D->preTranslate(-mPivotX, -mPivotY);
195                    mTransformMatrix3D->postTranslate(mPivotX + mTranslationX,
196                            mPivotY + mTranslationY);
197                    transformMatrix.postConcat(*mTransformMatrix3D);
198                    mTransformCamera->restore();
199
200                    mTransformMatrix->load(transformMatrix);
201                }
202            }
203        }
204        mMatrixDirty = false;
205    }
206}
207
208void DisplayList::outputViewProperties(const int level) {
209    updateMatrix();
210    if (mLeft != 0 || mTop != 0) {
211        ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", mLeft, mTop);
212    }
213    if (mStaticMatrix) {
214        ALOGD("%*sConcatMatrix (static) %p: " SK_MATRIX_STRING,
215                level * 2, "", mStaticMatrix, SK_MATRIX_ARGS(mStaticMatrix));
216    }
217    if (mAnimationMatrix) {
218        ALOGD("%*sConcatMatrix (animation) %p: " SK_MATRIX_STRING,
219                level * 2, "", mAnimationMatrix, SK_MATRIX_ARGS(mAnimationMatrix));
220    }
221    if (mMatrixFlags != 0) {
222        if (mMatrixFlags == TRANSLATION) {
223            ALOGD("%*sTranslate %.2f, %.2f, %.2f",
224                    level * 2, "", mTranslationX, mTranslationY, mTranslationZ);
225        } else {
226            ALOGD("%*sConcatMatrix %p: " MATRIX_4_STRING,
227                    level * 2, "", mTransformMatrix, MATRIX_4_ARGS(mTransformMatrix));
228        }
229    }
230
231    bool clipToBoundsNeeded = mCaching ? false : mClipToBounds;
232    if (mAlpha < 1) {
233        if (mCaching) {
234            ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mAlpha);
235        } else if (!mHasOverlappingRendering) {
236            ALOGD("%*sScaleAlpha %.2f", level * 2, "", mAlpha);
237        } else {
238            int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
239            if (clipToBoundsNeeded) {
240                flags |= SkCanvas::kClipToLayer_SaveFlag;
241                clipToBoundsNeeded = false; // clipping done by save layer
242            }
243            ALOGD("%*sSaveLayerAlpha %.2f, %.2f, %.2f, %.2f, %d, 0x%x", level * 2, "",
244                    (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop,
245                    (int)(mAlpha * 255), flags);
246        }
247    }
248    if (clipToBoundsNeeded) {
249        ALOGD("%*sClipRect %.2f, %.2f, %.2f, %.2f", level * 2, "", 0.0f, 0.0f,
250                (float) mRight - mLeft, (float) mBottom - mTop);
251    }
252}
253
254/*
255 * For property operations, we pass a savecount of 0, since the operations aren't part of the
256 * displaylist, and thus don't have to compensate for the record-time/playback-time discrepancy in
257 * base saveCount (i.e., how RestoreToCount uses saveCount + mCount)
258 */
259#define PROPERTY_SAVECOUNT 0
260
261template <class T>
262void DisplayList::setViewProperties(OpenGLRenderer& renderer, T& handler,
263        const int level) {
264#if DEBUG_DISPLAY_LIST
265    outputViewProperties(level);
266#endif
267    updateMatrix();
268    if (mLeft != 0 || mTop != 0) {
269        renderer.translate(mLeft, mTop);
270    }
271    if (mStaticMatrix) {
272        renderer.concatMatrix(mStaticMatrix);
273    } else if (mAnimationMatrix) {
274        renderer.concatMatrix(mAnimationMatrix);
275    }
276    if (mMatrixFlags != 0) {
277        if (mMatrixFlags == TRANSLATION) {
278            renderer.translate(mTranslationX, mTranslationY,
279                    Caches::getInstance().propertyEnable3d ? mTranslationZ : 0.0f); // TODO: necessary?
280        } else {
281            renderer.concatMatrix(*mTransformMatrix);
282        }
283    }
284    bool clipToBoundsNeeded = mCaching ? false : mClipToBounds;
285    if (mAlpha < 1) {
286        if (mCaching) {
287            renderer.setOverrideLayerAlpha(mAlpha);
288        } else if (!mHasOverlappingRendering) {
289            renderer.scaleAlpha(mAlpha);
290        } else {
291            // TODO: should be able to store the size of a DL at record time and not
292            // have to pass it into this call. In fact, this information might be in the
293            // location/size info that we store with the new native transform data.
294            int saveFlags = SkCanvas::kHasAlphaLayer_SaveFlag;
295            if (clipToBoundsNeeded) {
296                saveFlags |= SkCanvas::kClipToLayer_SaveFlag;
297                clipToBoundsNeeded = false; // clipping done by saveLayer
298            }
299
300            SaveLayerOp* op = new (handler.allocator()) SaveLayerOp(
301                    0, 0, mRight - mLeft, mBottom - mTop, mAlpha * 255, saveFlags);
302            handler(op, PROPERTY_SAVECOUNT, mClipToBounds);
303        }
304    }
305    if (clipToBoundsNeeded) {
306        ClipRectOp* op = new (handler.allocator()) ClipRectOp(0, 0,
307                mRight - mLeft, mBottom - mTop, SkRegion::kIntersect_Op);
308        handler(op, PROPERTY_SAVECOUNT, mClipToBounds);
309    }
310    if (CC_UNLIKELY(mClipToOutline && !mOutline.isEmpty())) {
311        ClipPathOp* op = new (handler.allocator()) ClipPathOp(&mOutline, SkRegion::kIntersect_Op);
312        handler(op, PROPERTY_SAVECOUNT, mClipToBounds);
313    }
314}
315
316/**
317 * Apply property-based transformations to input matrix
318 */
319void DisplayList::applyViewPropertyTransforms(mat4& matrix) {
320    if (mLeft != 0 || mTop != 0) {
321        matrix.translate(mLeft, mTop);
322    }
323    if (mStaticMatrix) {
324        mat4 stat(*mStaticMatrix);
325        matrix.multiply(stat);
326    } else if (mAnimationMatrix) {
327        mat4 anim(*mAnimationMatrix);
328        matrix.multiply(anim);
329    }
330    if (mMatrixFlags != 0) {
331        updateMatrix();
332        if (mMatrixFlags == TRANSLATION) {
333            matrix.translate(mTranslationX, mTranslationY, mTranslationZ);
334        } else {
335            matrix.multiply(*mTransformMatrix);
336        }
337    }
338}
339
340/**
341 * Organizes the DisplayList hierarchy to prepare for Z-based draw order.
342 *
343 * This should be called before a call to defer() or drawDisplayList()
344 *
345 * Each DisplayList that serves as a 3d root builds its list of composited children,
346 * which are flagged to not draw in the standard draw loop.
347 */
348void DisplayList::computeOrdering() {
349    ATRACE_CALL();
350    m3dNodes.clear();
351    mProjectedNodes.clear();
352
353    // TODO: create temporary DDLOp and call computeOrderingImpl on top DisplayList so that
354    // transform properties are applied correctly to top level children
355    if (mDisplayListData == NULL) return;
356    for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) {
357        DrawDisplayListOp* childOp = mDisplayListData->children[i];
358        childOp->mDisplayList->computeOrderingImpl(childOp,
359                &m3dNodes, &mat4::identity(),
360                &mProjectedNodes, &mat4::identity());
361    }
362}
363
364void DisplayList::computeOrderingImpl(
365        DrawDisplayListOp* opState,
366        Vector<ZDrawDisplayListOpPair>* compositedChildrenOf3dRoot,
367        const mat4* transformFrom3dRoot,
368        Vector<DrawDisplayListOp*>* compositedChildrenOfProjectionSurface,
369        const mat4* transformFromProjectionSurface) {
370    m3dNodes.clear();
371    mProjectedNodes.clear();
372    if (mDisplayListData == NULL || mDisplayListData->isEmpty()) return;
373
374    // TODO: should avoid this calculation in most cases
375    // TODO: just calculate single matrix, down to all leaf composited elements
376    Matrix4 localTransformFrom3dRoot(*transformFrom3dRoot);
377    localTransformFrom3dRoot.multiply(opState->mTransformFromParent);
378    Matrix4 localTransformFromProjectionSurface(*transformFromProjectionSurface);
379    localTransformFromProjectionSurface.multiply(opState->mTransformFromParent);
380
381    if (mTranslationZ != 0.0f) { // TODO: other signals for 3d compositing, such as custom matrix4
382        // composited 3d layer, flag for out of order draw and save matrix...
383        opState->mSkipInOrderDraw = true;
384        opState->mTransformFromCompositingAncestor.load(localTransformFrom3dRoot);
385
386        // ... and insert into current 3d root, keyed with pivot z for later sorting
387        Vector3 pivot(mPivotX, mPivotY, 0.0f);
388        mat4 totalTransform(localTransformFrom3dRoot);
389        applyViewPropertyTransforms(totalTransform);
390        totalTransform.mapPoint3d(pivot);
391        compositedChildrenOf3dRoot->add(ZDrawDisplayListOpPair(pivot.z, opState));
392    } else if (mProjectBackwards) {
393        // composited projectee, flag for out of order draw, save matrix, and store in proj surface
394        opState->mSkipInOrderDraw = true;
395        opState->mTransformFromCompositingAncestor.load(localTransformFromProjectionSurface);
396        compositedChildrenOfProjectionSurface->add(opState);
397    } else {
398        // standard in order draw
399        opState->mSkipInOrderDraw = false;
400    }
401
402    if (mDisplayListData->children.size() > 0) {
403        if (mIsolatedZVolume) {
404            // create a new 3d space for descendents by collecting them
405            compositedChildrenOf3dRoot = &m3dNodes;
406            transformFrom3dRoot = &mat4::identity();
407        } else {
408            applyViewPropertyTransforms(localTransformFrom3dRoot);
409            transformFrom3dRoot = &localTransformFrom3dRoot;
410        }
411
412        const bool isProjectionReceiver = mDisplayListData->projectionReceiveIndex >= 0;
413        bool haveAppliedPropertiesToProjection = false;
414        for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) {
415            DrawDisplayListOp* childOp = mDisplayListData->children[i];
416            DisplayList* child = childOp->mDisplayList;
417
418            Vector<DrawDisplayListOp*>* projectionChildren = NULL;
419            const mat4* projectionTransform = NULL;
420            if (isProjectionReceiver && !child->mProjectBackwards) {
421                // if receiving projections, collect projecting descendent
422
423                // Note that if a direct descendent is projecting backwards, we pass it's
424                // grandparent projection collection, since it shouldn't project onto it's
425                // parent, where it will already be drawing.
426                projectionChildren = &mProjectedNodes;
427                projectionTransform = &mat4::identity();
428            } else {
429                if (!haveAppliedPropertiesToProjection) {
430                    applyViewPropertyTransforms(localTransformFromProjectionSurface);
431                    haveAppliedPropertiesToProjection = true;
432                }
433                projectionChildren = compositedChildrenOfProjectionSurface;
434                projectionTransform = &localTransformFromProjectionSurface;
435            }
436            child->computeOrderingImpl(childOp,
437                    compositedChildrenOf3dRoot, transformFrom3dRoot,
438                    projectionChildren, projectionTransform);
439        }
440    }
441
442}
443
444class DeferOperationHandler {
445public:
446    DeferOperationHandler(DeferStateStruct& deferStruct, int level)
447        : mDeferStruct(deferStruct), mLevel(level) {}
448    inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) {
449        operation->defer(mDeferStruct, saveCount, mLevel, clipToBounds);
450    }
451    inline LinearAllocator& allocator() { return *(mDeferStruct.mAllocator); }
452
453private:
454    DeferStateStruct& mDeferStruct;
455    const int mLevel;
456};
457
458void DisplayList::defer(DeferStateStruct& deferStruct, const int level) {
459    DeferOperationHandler handler(deferStruct, level);
460    iterate<DeferOperationHandler>(deferStruct.mRenderer, handler, level);
461}
462
463class ReplayOperationHandler {
464public:
465    ReplayOperationHandler(ReplayStateStruct& replayStruct, int level)
466        : mReplayStruct(replayStruct), mLevel(level) {}
467    inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) {
468#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
469        mReplayStruct.mRenderer.eventMark(operation->name());
470#endif
471        operation->replay(mReplayStruct, saveCount, mLevel, clipToBounds);
472    }
473    inline LinearAllocator& allocator() { return *(mReplayStruct.mAllocator); }
474
475private:
476    ReplayStateStruct& mReplayStruct;
477    const int mLevel;
478};
479
480void DisplayList::replay(ReplayStateStruct& replayStruct, const int level) {
481    ReplayOperationHandler handler(replayStruct, level);
482
483    replayStruct.mRenderer.startMark(mName.string());
484    iterate<ReplayOperationHandler>(replayStruct.mRenderer, handler, level);
485    replayStruct.mRenderer.endMark();
486
487    DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", level * 2, "", this, mName.string(),
488            replayStruct.mDrawGlStatus);
489}
490
491template <class T>
492void DisplayList::iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& renderer,
493        T& handler, const int level) {
494    if (m3dNodes.size() == 0 ||
495            (mode == kNegativeZChildren && m3dNodes[0].key > 0.0f) ||
496            (mode == kPositiveZChildren && m3dNodes[m3dNodes.size() - 1].key < 0.0f)) {
497        // no 3d children to draw
498        return;
499    }
500
501    int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
502    LinearAllocator& alloc = handler.allocator();
503    ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, mWidth, mHeight,
504            SkRegion::kIntersect_Op); // clip to 3d root bounds for now
505    handler(clipOp, PROPERTY_SAVECOUNT, mClipToBounds);
506
507    for (size_t i = 0; i < m3dNodes.size(); i++) {
508        const float zValue = m3dNodes[i].key;
509        DrawDisplayListOp* childOp = m3dNodes[i].value;
510
511        if (mode == kPositiveZChildren && zValue < 0.0f) continue;
512        if (mode == kNegativeZChildren && zValue > 0.0f) break;
513
514        DisplayList* child = childOp->mDisplayList;
515        if (mode == kPositiveZChildren && zValue > 0.0f
516                && child->mCastsShadow && child->mAlpha > 0.0f) {
517            /* draw shadow with parent matrix applied, passing in the child's total matrix
518             * TODO: consider depth in more complex scenarios (neg z, added shadow depth)
519             */
520            mat4 shadowMatrix(childOp->mTransformFromCompositingAncestor);
521            child->applyViewPropertyTransforms(shadowMatrix);
522
523            DisplayListOp* shadowOp  = new (alloc) DrawShadowOp(shadowMatrix,
524                    child->mAlpha, &(child->mOutline), child->mWidth, child->mHeight);
525            handler(shadowOp, PROPERTY_SAVECOUNT, mClipToBounds);
526        }
527
528        renderer.concatMatrix(childOp->mTransformFromCompositingAncestor);
529        childOp->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone
530        handler(childOp, renderer.getSaveCount() - 1, mClipToBounds);
531        childOp->mSkipInOrderDraw = true;
532    }
533    handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, mClipToBounds);
534}
535
536template <class T>
537void DisplayList::iterateProjectedChildren(OpenGLRenderer& renderer, T& handler, const int level) {
538    int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
539    LinearAllocator& alloc = handler.allocator();
540    ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, mWidth, mHeight,
541            SkRegion::kReplace_Op); // clip to projection surface root bounds
542    handler(clipOp, PROPERTY_SAVECOUNT, mClipToBounds);
543
544    for (size_t i = 0; i < mProjectedNodes.size(); i++) {
545        DrawDisplayListOp* childOp = mProjectedNodes[i];
546
547        // matrix save, concat, and restore can be done safely without allocating operations
548        int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag);
549        renderer.concatMatrix(childOp->mTransformFromCompositingAncestor);
550        childOp->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone
551        handler(childOp, renderer.getSaveCount() - 1, mClipToBounds);
552        childOp->mSkipInOrderDraw = true;
553        renderer.restoreToCount(restoreTo);
554    }
555    handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, mClipToBounds);
556}
557
558/**
559 * This function serves both defer and replay modes, and will organize the displayList's component
560 * operations for a single frame:
561 *
562 * Every 'simple' state operation that affects just the matrix and alpha (or other factors of
563 * DeferredDisplayState) may be issued directly to the renderer, but complex operations (with custom
564 * defer logic) and operations in displayListOps are issued through the 'handler' which handles the
565 * defer vs replay logic, per operation
566 */
567template <class T>
568void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level) {
569    if (CC_UNLIKELY(mDestroyed)) { // temporary debug logging
570        ALOGW("Error: %s is drawing after destruction", getName());
571        CRASH();
572    }
573    if (mDisplayListData->isEmpty() || mAlpha <= 0) {
574        DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, mName.string());
575        return;
576    }
577
578#if DEBUG_DISPLAY_LIST
579    Rect* clipRect = renderer.getClipRect();
580    DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.0f, %.0f, %.0f",
581            level * 2, "", this, mName.string(), clipRect->left, clipRect->top,
582            clipRect->right, clipRect->bottom);
583#endif
584
585    LinearAllocator& alloc = handler.allocator();
586    int restoreTo = renderer.getSaveCount();
587    handler(new (alloc) SaveOp(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag),
588            PROPERTY_SAVECOUNT, mClipToBounds);
589
590    DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "",
591            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
592
593    setViewProperties<T>(renderer, handler, level + 1);
594
595    bool quickRejected = mClipToBounds && renderer.quickRejectConservative(0, 0, mWidth, mHeight);
596    if (!quickRejected) {
597        // Z sort 3d children (stable-ness makes z compare fall back to standard drawing order)
598        std::stable_sort(m3dNodes.begin(), m3dNodes.end());
599
600        // for 3d root, draw children with negative z values
601        iterate3dChildren(kNegativeZChildren, renderer, handler, level);
602
603        DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
604        const int saveCountOffset = renderer.getSaveCount() - 1;
605        const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex;
606        for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
607            DisplayListOp *op = mDisplayListData->displayListOps[i];
608
609#if DEBUG_DISPLAY_LIST
610            op->output(level + 1);
611#endif
612
613            logBuffer.writeCommand(level, op->name());
614            handler(op, saveCountOffset, mClipToBounds);
615
616            if (CC_UNLIKELY(i == projectionReceiveIndex && mProjectedNodes.size() > 0)) {
617                iterateProjectedChildren(renderer, handler, level);
618            }
619        }
620
621        // for 3d root, draw children with positive z values
622        iterate3dChildren(kPositiveZChildren, renderer, handler, level);
623    }
624
625    DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
626    handler(new (alloc) RestoreToCountOp(restoreTo),
627            PROPERTY_SAVECOUNT, mClipToBounds);
628    renderer.setOverrideLayerAlpha(1.0f);
629}
630
631void DisplayListData::cleanupResources() {
632    Caches& caches = Caches::getInstance();
633    caches.unregisterFunctors(functorCount);
634    caches.resourceCache.lock();
635
636    for (size_t i = 0; i < bitmapResources.size(); i++) {
637        caches.resourceCache.decrementRefcountLocked(bitmapResources.itemAt(i));
638    }
639
640    for (size_t i = 0; i < ownedBitmapResources.size(); i++) {
641        const SkBitmap* bitmap = ownedBitmapResources.itemAt(i);
642        caches.resourceCache.decrementRefcountLocked(bitmap);
643        caches.resourceCache.destructorLocked(bitmap);
644    }
645
646    for (size_t i = 0; i < patchResources.size(); i++) {
647        caches.resourceCache.decrementRefcountLocked(patchResources.itemAt(i));
648    }
649
650    for (size_t i = 0; i < shaders.size(); i++) {
651        caches.resourceCache.decrementRefcountLocked(shaders.itemAt(i));
652        caches.resourceCache.destructorLocked(shaders.itemAt(i));
653    }
654
655    for (size_t i = 0; i < sourcePaths.size(); i++) {
656        caches.resourceCache.decrementRefcountLocked(sourcePaths.itemAt(i));
657    }
658
659    for (size_t i = 0; i < layers.size(); i++) {
660        caches.resourceCache.decrementRefcountLocked(layers.itemAt(i));
661    }
662
663    caches.resourceCache.unlock();
664
665    for (size_t i = 0; i < paints.size(); i++) {
666        delete paints.itemAt(i);
667    }
668
669    for (size_t i = 0; i < regions.size(); i++) {
670        delete regions.itemAt(i);
671    }
672
673    for (size_t i = 0; i < paths.size(); i++) {
674        delete paths.itemAt(i);
675    }
676
677    for (size_t i = 0; i < matrices.size(); i++) {
678        delete matrices.itemAt(i);
679    }
680
681    bitmapResources.clear();
682    ownedBitmapResources.clear();
683    patchResources.clear();
684    shaders.clear();
685    sourcePaths.clear();
686    paints.clear();
687    regions.clear();
688    paths.clear();
689    matrices.clear();
690    layers.clear();
691}
692
693}; // namespace uirenderer
694}; // namespace android
695