DisplayList.cpp revision 5d11676414b3606792e23c269cf75b44faa1a2af
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 "Debug.h"
18#include "DisplayList.h"
19#include "DisplayListOp.h"
20#include "DisplayListLogBuffer.h"
21
22namespace android {
23namespace uirenderer {
24
25void DisplayList::outputLogBuffer(int fd) {
26    DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
27    if (logBuffer.isEmpty()) {
28        return;
29    }
30
31    FILE *file = fdopen(fd, "a");
32
33    fprintf(file, "\nRecent DisplayList operations\n");
34    logBuffer.outputCommands(file);
35
36    String8 cachesLog;
37    Caches::getInstance().dumpMemoryUsage(cachesLog);
38    fprintf(file, "\nCaches:\n%s", cachesLog.string());
39    fprintf(file, "\n");
40
41    fflush(file);
42}
43
44DisplayList::DisplayList(const DisplayListRenderer& recorder) :
45    mTransformMatrix(NULL), mTransformCamera(NULL), mTransformMatrix3D(NULL),
46    mStaticMatrix(NULL), mAnimationMatrix(NULL) {
47
48    initFromDisplayListRenderer(recorder);
49}
50
51DisplayList::~DisplayList() {
52    clearResources();
53}
54
55void DisplayList::destroyDisplayListDeferred(DisplayList* displayList) {
56    if (displayList) {
57        DISPLAY_LIST_LOGD("Deferring display list destruction");
58        Caches::getInstance().deleteDisplayListDeferred(displayList);
59    }
60}
61
62void DisplayList::clearResources() {
63    mDisplayListData = NULL;
64    delete mTransformMatrix;
65    delete mTransformCamera;
66    delete mTransformMatrix3D;
67    delete mStaticMatrix;
68    delete mAnimationMatrix;
69
70    mTransformMatrix = NULL;
71    mTransformCamera = NULL;
72    mTransformMatrix3D = NULL;
73    mStaticMatrix = NULL;
74    mAnimationMatrix = NULL;
75
76    Caches& caches = Caches::getInstance();
77    caches.unregisterFunctors(mFunctorCount);
78    caches.resourceCache.lock();
79
80    for (size_t i = 0; i < mBitmapResources.size(); i++) {
81        caches.resourceCache.decrementRefcountLocked(mBitmapResources.itemAt(i));
82    }
83
84    for (size_t i = 0; i < mOwnedBitmapResources.size(); i++) {
85        SkBitmap* bitmap = mOwnedBitmapResources.itemAt(i);
86        caches.resourceCache.decrementRefcountLocked(bitmap);
87        caches.resourceCache.destructorLocked(bitmap);
88    }
89
90    for (size_t i = 0; i < mFilterResources.size(); i++) {
91        caches.resourceCache.decrementRefcountLocked(mFilterResources.itemAt(i));
92    }
93
94    for (size_t i = 0; i < mShaders.size(); i++) {
95        caches.resourceCache.decrementRefcountLocked(mShaders.itemAt(i));
96        caches.resourceCache.destructorLocked(mShaders.itemAt(i));
97    }
98
99    for (size_t i = 0; i < mSourcePaths.size(); i++) {
100        caches.resourceCache.decrementRefcountLocked(mSourcePaths.itemAt(i));
101    }
102
103    for (size_t i = 0; i < mLayers.size(); i++) {
104        caches.resourceCache.decrementRefcountLocked(mLayers.itemAt(i));
105    }
106
107    caches.resourceCache.unlock();
108
109    for (size_t i = 0; i < mPaints.size(); i++) {
110        delete mPaints.itemAt(i);
111    }
112
113    for (size_t i = 0; i < mRegions.size(); i++) {
114        delete mRegions.itemAt(i);
115    }
116
117    for (size_t i = 0; i < mPaths.size(); i++) {
118        SkPath* path = mPaths.itemAt(i);
119        caches.pathCache.remove(path);
120        delete path;
121    }
122
123    for (size_t i = 0; i < mMatrices.size(); i++) {
124        delete mMatrices.itemAt(i);
125    }
126
127    mBitmapResources.clear();
128    mOwnedBitmapResources.clear();
129    mFilterResources.clear();
130    mShaders.clear();
131    mSourcePaths.clear();
132    mPaints.clear();
133    mRegions.clear();
134    mPaths.clear();
135    mMatrices.clear();
136    mLayers.clear();
137}
138
139void DisplayList::reset() {
140    clearResources();
141    init();
142}
143
144void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing) {
145    if (reusing) {
146        // re-using display list - clear out previous allocations
147        clearResources();
148    }
149
150    init();
151
152    mDisplayListData = recorder.getDisplayListData();
153    mSize = mDisplayListData->allocator.usedSize();
154
155    if (mSize == 0) {
156        return;
157    }
158
159    mFunctorCount = recorder.getFunctorCount();
160
161    Caches& caches = Caches::getInstance();
162    caches.registerFunctors(mFunctorCount);
163    caches.resourceCache.lock();
164
165    const Vector<SkBitmap*>& bitmapResources = recorder.getBitmapResources();
166    for (size_t i = 0; i < bitmapResources.size(); i++) {
167        SkBitmap* resource = bitmapResources.itemAt(i);
168        mBitmapResources.add(resource);
169        caches.resourceCache.incrementRefcountLocked(resource);
170    }
171
172    const Vector<SkBitmap*> &ownedBitmapResources = recorder.getOwnedBitmapResources();
173    for (size_t i = 0; i < ownedBitmapResources.size(); i++) {
174        SkBitmap* resource = ownedBitmapResources.itemAt(i);
175        mOwnedBitmapResources.add(resource);
176        caches.resourceCache.incrementRefcountLocked(resource);
177    }
178
179    const Vector<SkiaColorFilter*>& filterResources = recorder.getFilterResources();
180    for (size_t i = 0; i < filterResources.size(); i++) {
181        SkiaColorFilter* resource = filterResources.itemAt(i);
182        mFilterResources.add(resource);
183        caches.resourceCache.incrementRefcountLocked(resource);
184    }
185
186    const Vector<SkiaShader*>& shaders = recorder.getShaders();
187    for (size_t i = 0; i < shaders.size(); i++) {
188        SkiaShader* resource = shaders.itemAt(i);
189        mShaders.add(resource);
190        caches.resourceCache.incrementRefcountLocked(resource);
191    }
192
193    const SortedVector<SkPath*>& sourcePaths = recorder.getSourcePaths();
194    for (size_t i = 0; i < sourcePaths.size(); i++) {
195        mSourcePaths.add(sourcePaths.itemAt(i));
196        caches.resourceCache.incrementRefcountLocked(sourcePaths.itemAt(i));
197    }
198
199    const Vector<Layer*>& layers = recorder.getLayers();
200    for (size_t i = 0; i < layers.size(); i++) {
201        mLayers.add(layers.itemAt(i));
202        caches.resourceCache.incrementRefcountLocked(layers.itemAt(i));
203    }
204
205    caches.resourceCache.unlock();
206
207    mPaints.appendVector(recorder.getPaints());
208    mRegions.appendVector(recorder.getRegions());
209    mPaths.appendVector(recorder.getPaths());
210    mMatrices.appendVector(recorder.getMatrices());
211}
212
213void DisplayList::init() {
214    mSize = 0;
215    mIsRenderable = true;
216    mFunctorCount = 0;
217    mLeft = 0;
218    mTop = 0;
219    mRight = 0;
220    mBottom = 0;
221    mClipChildren = true;
222    mAlpha = 1;
223    mMultipliedAlpha = 255;
224    mHasOverlappingRendering = true;
225    mTranslationX = 0;
226    mTranslationY = 0;
227    mRotation = 0;
228    mRotationX = 0;
229    mRotationY= 0;
230    mScaleX = 1;
231    mScaleY = 1;
232    mPivotX = 0;
233    mPivotY = 0;
234    mCameraDistance = 0;
235    mMatrixDirty = false;
236    mMatrixFlags = 0;
237    mPrevWidth = -1;
238    mPrevHeight = -1;
239    mWidth = 0;
240    mHeight = 0;
241    mPivotExplicitlySet = false;
242    mCaching = false;
243}
244
245size_t DisplayList::getSize() {
246    return mSize;
247}
248
249/**
250 * This function is a simplified version of replay(), where we simply retrieve and log the
251 * display list. This function should remain in sync with the replay() function.
252 */
253void DisplayList::output(uint32_t level) {
254    ALOGD("%*sStart display list (%p, %s, render=%d)", level * 2, "", this,
255            mName.string(), isRenderable());
256
257    ALOGD("%*s%s %d", level * 2, "", "Save", SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
258    outputViewProperties(level);
259    int flags = DisplayListOp::kOpLogFlag_Recurse;
260    for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
261        mDisplayListData->displayListOps[i]->output(level, flags);
262    }
263    ALOGD("%*sDone (%p, %s)", level * 2, "", this, mName.string());
264}
265
266void DisplayList::updateMatrix() {
267    if (mMatrixDirty) {
268        if (!mTransformMatrix) {
269            mTransformMatrix = new SkMatrix();
270        }
271        if (mMatrixFlags == 0 || mMatrixFlags == TRANSLATION) {
272            mTransformMatrix->reset();
273        } else {
274            if (!mPivotExplicitlySet) {
275                if (mWidth != mPrevWidth || mHeight != mPrevHeight) {
276                    mPrevWidth = mWidth;
277                    mPrevHeight = mHeight;
278                    mPivotX = mPrevWidth / 2;
279                    mPivotY = mPrevHeight / 2;
280                }
281            }
282            if ((mMatrixFlags & ROTATION_3D) == 0) {
283                mTransformMatrix->setTranslate(mTranslationX, mTranslationY);
284                mTransformMatrix->preRotate(mRotation, mPivotX, mPivotY);
285                mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY);
286            } else {
287                if (!mTransformCamera) {
288                    mTransformCamera = new Sk3DView();
289                    mTransformMatrix3D = new SkMatrix();
290                }
291                mTransformMatrix->reset();
292                mTransformCamera->save();
293                mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY);
294                mTransformCamera->rotateX(mRotationX);
295                mTransformCamera->rotateY(mRotationY);
296                mTransformCamera->rotateZ(-mRotation);
297                mTransformCamera->getMatrix(mTransformMatrix3D);
298                mTransformMatrix3D->preTranslate(-mPivotX, -mPivotY);
299                mTransformMatrix3D->postTranslate(mPivotX + mTranslationX,
300                        mPivotY + mTranslationY);
301                mTransformMatrix->postConcat(*mTransformMatrix3D);
302                mTransformCamera->restore();
303            }
304        }
305        mMatrixDirty = false;
306    }
307}
308
309void DisplayList::outputViewProperties(uint32_t level) {
310    updateMatrix();
311    if (mLeft != 0 || mTop != 0) {
312        ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", mLeft, mTop);
313    }
314    if (mStaticMatrix) {
315        ALOGD("%*sConcatMatrix (static) %p: " MATRIX_STRING,
316                level * 2, "", mStaticMatrix, MATRIX_ARGS(mStaticMatrix));
317    }
318    if (mAnimationMatrix) {
319        ALOGD("%*sConcatMatrix (animation) %p: " MATRIX_STRING,
320                level * 2, "", mAnimationMatrix, MATRIX_ARGS(mStaticMatrix));
321    }
322    if (mMatrixFlags != 0) {
323        if (mMatrixFlags == TRANSLATION) {
324            ALOGD("%*sTranslate %f, %f", level * 2, "", mTranslationX, mTranslationY);
325        } else {
326            ALOGD("%*sConcatMatrix %p: " MATRIX_STRING,
327                    level * 2, "", mTransformMatrix, MATRIX_ARGS(mTransformMatrix));
328        }
329    }
330    if (mAlpha < 1 && !mCaching) {
331        if (!mHasOverlappingRendering) {
332            ALOGD("%*sSetAlpha %.2f", level * 2, "", mAlpha);
333        } else {
334            int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
335            if (mClipChildren) {
336                flags |= SkCanvas::kClipToLayer_SaveFlag;
337            }
338            ALOGD("%*sSaveLayerAlpha %.2f, %.2f, %.2f, %.2f, %d, 0x%x", level * 2, "",
339                    (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop,
340                    mMultipliedAlpha, flags);
341        }
342    }
343    if (mClipChildren && !mCaching) {
344        ALOGD("%*sClipRect %.2f, %.2f, %.2f, %.2f", level * 2, "", 0.0f, 0.0f,
345                (float) mRight - mLeft, (float) mBottom - mTop);
346    }
347}
348
349void DisplayList::setViewProperties(OpenGLRenderer& renderer, uint32_t level) {
350#if DEBUG_DISPLAYLIST
351    outputViewProperties(level);
352#endif
353    updateMatrix();
354    if (mLeft != 0 || mTop != 0) {
355        renderer.translate(mLeft, mTop);
356    }
357    if (mStaticMatrix) {
358        renderer.concatMatrix(mStaticMatrix);
359    } else if (mAnimationMatrix) {
360        renderer.concatMatrix(mAnimationMatrix);
361    }
362    if (mMatrixFlags != 0) {
363        if (mMatrixFlags == TRANSLATION) {
364            renderer.translate(mTranslationX, mTranslationY);
365        } else {
366            renderer.concatMatrix(mTransformMatrix);
367        }
368    }
369    if (mAlpha < 1 && !mCaching) {
370        if (!mHasOverlappingRendering) {
371            renderer.setAlpha(mAlpha);
372        } else {
373            // TODO: should be able to store the size of a DL at record time and not
374            // have to pass it into this call. In fact, this information might be in the
375            // location/size info that we store with the new native transform data.
376            int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
377            if (mClipChildren) {
378                flags |= SkCanvas::kClipToLayer_SaveFlag;
379            }
380            renderer.saveLayerAlpha(0, 0, mRight - mLeft, mBottom - mTop,
381                    mMultipliedAlpha, flags);
382        }
383    }
384    if (mClipChildren && !mCaching) {
385        renderer.clipRect(0, 0, mRight - mLeft, mBottom - mTop,
386                SkRegion::kIntersect_Op);
387    }
388}
389
390status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level,
391        DeferredDisplayList* deferredList) {
392    status_t drawGlStatus = DrawGlInfo::kStatusDone;
393
394#if DEBUG_DISPLAY_LIST
395    Rect* clipRect = renderer.getClipRect();
396    DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.f, %.0f, %.0f",
397            (level+1)*2, "", this, mName.string(), clipRect->left, clipRect->top,
398            clipRect->right, clipRect->bottom);
399#endif
400
401    renderer.startMark(mName.string());
402
403    int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
404    DISPLAY_LIST_LOGD("%*sSave %d %d", level * 2, "",
405            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
406
407    if (mAlpha < 1 && !mCaching && CC_LIKELY(deferredList)) {
408        // flush before a saveLayerAlpha/setAlpha
409        // TODO: make this cleaner
410        drawGlStatus |= deferredList->flush(renderer, dirty, flags, level);
411    }
412    setViewProperties(renderer, level);
413
414    if (renderer.quickRejectNoScissor(0, 0, mWidth, mHeight)) {
415        DISPLAY_LIST_LOGD("%*sRestoreToCount %d", level * 2, "", restoreTo);
416        renderer.restoreToCount(restoreTo);
417        renderer.endMark();
418        return drawGlStatus;
419    }
420
421    DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
422    int saveCount = renderer.getSaveCount() - 1;
423    for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
424        DisplayListOp *op = mDisplayListData->displayListOps[i];
425#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
426        Caches::getInstance().eventMark(strlen(op->name()), op->name());
427#endif
428
429        drawGlStatus |= op->replay(renderer, dirty, flags,
430                saveCount, level, mCaching, mMultipliedAlpha, deferredList);
431        logBuffer.writeCommand(level, op->name());
432    }
433
434    DISPLAY_LIST_LOGD("%*sRestoreToCount %d", level * 2, "", restoreTo);
435    renderer.restoreToCount(restoreTo);
436    renderer.endMark();
437
438    DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", (level + 1) * 2, "", this, mName.string(),
439            drawGlStatus);
440
441    if (!level && CC_LIKELY(deferredList)) {
442        drawGlStatus |= deferredList->flush(renderer, dirty, flags, level);
443    }
444
445    return drawGlStatus;
446}
447
448}; // namespace uirenderer
449}; // namespace android
450