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