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