DisplayList.cpp revision e3b0a0117a2ab4118f868a731b238fe8f2430276
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
24namespace android {
25namespace uirenderer {
26
27void 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
46DisplayList::DisplayList(const DisplayListRenderer& recorder) :
47    mDestroyed(false), mTransformMatrix(NULL), mTransformCamera(NULL), mTransformMatrix3D(NULL),
48    mStaticMatrix(NULL), mAnimationMatrix(NULL) {
49
50    initFromDisplayListRenderer(recorder);
51}
52
53DisplayList::~DisplayList() {
54    mDestroyed = true;
55    clearResources();
56}
57
58void DisplayList::destroyDisplayListDeferred(DisplayList* displayList) {
59    if (displayList) {
60        DISPLAY_LIST_LOGD("Deferring display list destruction");
61        Caches::getInstance().deleteDisplayListDeferred(displayList);
62    }
63}
64
65void 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
151void DisplayList::reset() {
152    clearResources();
153    init();
154}
155
156void 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
243void 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
274size_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 */
282void 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
297float DisplayList::getPivotX() {
298    updateMatrix();
299    return mPivotX;
300}
301
302float DisplayList::getPivotY() {
303    updateMatrix();
304    return mPivotY;
305}
306
307void 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
350void 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(mStaticMatrix));
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 = mClipToBounds;
373    if (mAlpha < 1) {
374        if (mCaching) {
375            ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mAlpha);
376            clipToBoundsNeeded = false; // clipping done by layer
377        } else if (!mHasOverlappingRendering) {
378            ALOGD("%*sScaleAlpha %.2f", level * 2, "", mAlpha);
379        } else {
380            int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
381            if (clipToBoundsNeeded) {
382                flags |= SkCanvas::kClipToLayer_SaveFlag;
383                clipToBoundsNeeded = false; // clipping done by save layer
384            }
385            ALOGD("%*sSaveLayerAlpha %.2f, %.2f, %.2f, %.2f, %d, 0x%x", level * 2, "",
386                    (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop,
387                    (int)(mAlpha * 255), flags);
388        }
389    }
390    if (clipToBoundsNeeded) {
391        ALOGD("%*sClipRect %.2f, %.2f, %.2f, %.2f", level * 2, "", 0.0f, 0.0f,
392                (float) mRight - mLeft, (float) mBottom - mTop);
393    }
394}
395
396/*
397 * For property operations, we pass a savecount of 0, since the operations aren't part of the
398 * displaylist, and thus don't have to compensate for the record-time/playback-time discrepancy in
399 * base saveCount (i.e., how RestoreToCount uses saveCount + mCount)
400 */
401#define PROPERTY_SAVECOUNT 0
402
403template <class T>
404void DisplayList::setViewProperties(OpenGLRenderer& renderer, T& handler,
405        const int level) {
406#if DEBUG_DISPLAY_LIST
407    outputViewProperties(level);
408#endif
409    updateMatrix();
410    if (mLeft != 0 || mTop != 0) {
411        renderer.translate(mLeft, mTop);
412    }
413    if (mStaticMatrix) {
414        renderer.concatMatrix(mStaticMatrix);
415    } else if (mAnimationMatrix) {
416        renderer.concatMatrix(mAnimationMatrix);
417    }
418    if (mMatrixFlags != 0) {
419        if (mMatrixFlags == TRANSLATION) {
420            renderer.translate(mTranslationX, mTranslationY);
421        } else {
422            renderer.concatMatrix(mTransformMatrix);
423        }
424    }
425    bool clipToBoundsNeeded = mClipToBounds;
426    if (mAlpha < 1) {
427        if (mCaching) {
428            renderer.setOverrideLayerAlpha(mAlpha);
429            clipToBoundsNeeded = false; // clipping done by layer
430        } else if (!mHasOverlappingRendering) {
431            renderer.scaleAlpha(mAlpha);
432        } else {
433            // TODO: should be able to store the size of a DL at record time and not
434            // have to pass it into this call. In fact, this information might be in the
435            // location/size info that we store with the new native transform data.
436            int saveFlags = SkCanvas::kHasAlphaLayer_SaveFlag;
437            if (clipToBoundsNeeded) {
438                saveFlags |= SkCanvas::kClipToLayer_SaveFlag;
439                clipToBoundsNeeded = false; // clipping done by saveLayer
440            }
441            handler(mSaveLayerOp->reinit(0, 0, mRight - mLeft, mBottom - mTop,
442                    mAlpha * 255, SkXfermode::kSrcOver_Mode, saveFlags), PROPERTY_SAVECOUNT,
443                    mClipToBounds);
444        }
445    }
446    if (clipToBoundsNeeded) {
447        handler(mClipRectOp->reinit(0, 0, mRight - mLeft, mBottom - mTop, SkRegion::kIntersect_Op),
448                PROPERTY_SAVECOUNT, mClipToBounds);
449    }
450}
451
452class DeferOperationHandler {
453public:
454    DeferOperationHandler(DeferStateStruct& deferStruct, int level)
455        : mDeferStruct(deferStruct), mLevel(level) {}
456    inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) {
457        operation->defer(mDeferStruct, saveCount, mLevel, clipToBounds);
458    }
459private:
460    DeferStateStruct& mDeferStruct;
461    const int mLevel;
462};
463
464void DisplayList::defer(DeferStateStruct& deferStruct, const int level) {
465    DeferOperationHandler handler(deferStruct, level);
466    iterate<DeferOperationHandler>(deferStruct.mRenderer, handler, level);
467}
468
469class ReplayOperationHandler {
470public:
471    ReplayOperationHandler(ReplayStateStruct& replayStruct, int level)
472        : mReplayStruct(replayStruct), mLevel(level) {}
473    inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) {
474#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
475        mReplayStruct.mRenderer.eventMark(operation->name());
476#endif
477        operation->replay(mReplayStruct, saveCount, mLevel, clipToBounds);
478    }
479private:
480    ReplayStateStruct& mReplayStruct;
481    const int mLevel;
482};
483
484void DisplayList::replay(ReplayStateStruct& replayStruct, const int level) {
485    ReplayOperationHandler handler(replayStruct, level);
486
487    replayStruct.mRenderer.startMark(mName.string());
488    iterate<ReplayOperationHandler>(replayStruct.mRenderer, handler, level);
489    replayStruct.mRenderer.endMark();
490
491    DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", level * 2, "", this, mName.string(),
492            replayStruct.mDrawGlStatus);
493}
494
495/**
496 * This function serves both defer and replay modes, and will organize the displayList's component
497 * operations for a single frame:
498 *
499 * Every 'simple' operation that affects just the matrix and alpha (or other factors of
500 * DeferredDisplayState) may be issued directly to the renderer, but complex operations (with custom
501 * defer logic) and operations in displayListOps are issued through the 'handler' which handles the
502 * defer vs replay logic, per operation
503 */
504template <class T>
505void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level) {
506    if (CC_UNLIKELY(mDestroyed)) { // temporary debug logging
507        ALOGW("Error: %s is drawing after destruction, size %d", getName(), mSize);
508        CRASH();
509    }
510    if (mSize == 0 || mAlpha <= 0) {
511        DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, mName.string());
512        return;
513    }
514
515#if DEBUG_DISPLAY_LIST
516    Rect* clipRect = renderer.getClipRect();
517    DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.0f, %.0f, %.0f",
518            level * 2, "", this, mName.string(), clipRect->left, clipRect->top,
519            clipRect->right, clipRect->bottom);
520#endif
521
522    int restoreTo = renderer.getSaveCount();
523    handler(mSaveOp->reinit(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag),
524            PROPERTY_SAVECOUNT, mClipToBounds);
525
526    DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "",
527            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
528
529    setViewProperties<T>(renderer, handler, level + 1);
530
531    if (mClipToBounds && renderer.quickRejectNoScissor(0, 0, mWidth, mHeight)) {
532        DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
533        handler(mRestoreToCountOp->reinit(restoreTo), PROPERTY_SAVECOUNT, mClipToBounds);
534        renderer.restoreToCount(restoreTo);
535        renderer.setOverrideLayerAlpha(1.0f);
536        return;
537    }
538
539    DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
540    int saveCount = renderer.getSaveCount() - 1;
541    for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
542        DisplayListOp *op = mDisplayListData->displayListOps[i];
543
544#if DEBUG_DISPLAY_LIST
545        op->output(level + 1);
546#endif
547
548        logBuffer.writeCommand(level, op->name());
549        handler(op, saveCount, mClipToBounds);
550    }
551
552    DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
553    handler(mRestoreToCountOp->reinit(restoreTo), PROPERTY_SAVECOUNT, mClipToBounds);
554    renderer.restoreToCount(restoreTo);
555    renderer.setOverrideLayerAlpha(1.0f);
556}
557
558}; // namespace uirenderer
559}; // namespace android
560