DisplayList.cpp revision 52036b19a5f82bc4d75cfcbff99c65df8d25a99b
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
266float DisplayList::getPivotX() {
267    updateMatrix();
268    return mPivotX;
269}
270
271float DisplayList::getPivotY() {
272    updateMatrix();
273    return mPivotY;
274}
275
276void DisplayList::updateMatrix() {
277    if (mMatrixDirty) {
278        if (!mTransformMatrix) {
279            mTransformMatrix = new SkMatrix();
280        }
281        if (mMatrixFlags == 0 || mMatrixFlags == TRANSLATION) {
282            mTransformMatrix->reset();
283        } else {
284            if (!mPivotExplicitlySet) {
285                if (mWidth != mPrevWidth || mHeight != mPrevHeight) {
286                    mPrevWidth = mWidth;
287                    mPrevHeight = mHeight;
288                    mPivotX = mPrevWidth / 2;
289                    mPivotY = mPrevHeight / 2;
290                }
291            }
292            if ((mMatrixFlags & ROTATION_3D) == 0) {
293                mTransformMatrix->setTranslate(mTranslationX, mTranslationY);
294                mTransformMatrix->preRotate(mRotation, mPivotX, mPivotY);
295                mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY);
296            } else {
297                if (!mTransformCamera) {
298                    mTransformCamera = new Sk3DView();
299                    mTransformMatrix3D = new SkMatrix();
300                }
301                mTransformMatrix->reset();
302                mTransformCamera->save();
303                mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY);
304                mTransformCamera->rotateX(mRotationX);
305                mTransformCamera->rotateY(mRotationY);
306                mTransformCamera->rotateZ(-mRotation);
307                mTransformCamera->getMatrix(mTransformMatrix3D);
308                mTransformMatrix3D->preTranslate(-mPivotX, -mPivotY);
309                mTransformMatrix3D->postTranslate(mPivotX + mTranslationX,
310                        mPivotY + mTranslationY);
311                mTransformMatrix->postConcat(*mTransformMatrix3D);
312                mTransformCamera->restore();
313            }
314        }
315        mMatrixDirty = false;
316    }
317}
318
319void DisplayList::outputViewProperties(uint32_t level) {
320    updateMatrix();
321    if (mLeft != 0 || mTop != 0) {
322        ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", mLeft, mTop);
323    }
324    if (mStaticMatrix) {
325        ALOGD("%*sConcatMatrix (static) %p: " MATRIX_STRING,
326                level * 2, "", mStaticMatrix, MATRIX_ARGS(mStaticMatrix));
327    }
328    if (mAnimationMatrix) {
329        ALOGD("%*sConcatMatrix (animation) %p: " MATRIX_STRING,
330                level * 2, "", mAnimationMatrix, MATRIX_ARGS(mStaticMatrix));
331    }
332    if (mMatrixFlags != 0) {
333        if (mMatrixFlags == TRANSLATION) {
334            ALOGD("%*sTranslate %f, %f", level * 2, "", mTranslationX, mTranslationY);
335        } else {
336            ALOGD("%*sConcatMatrix %p: " MATRIX_STRING,
337                    level * 2, "", mTransformMatrix, MATRIX_ARGS(mTransformMatrix));
338        }
339    }
340    if (mAlpha < 1 && !mCaching) {
341        if (!mHasOverlappingRendering) {
342            ALOGD("%*sSetAlpha %.2f", level * 2, "", mAlpha);
343        } else {
344            int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
345            if (mClipChildren) {
346                flags |= SkCanvas::kClipToLayer_SaveFlag;
347            }
348            ALOGD("%*sSaveLayerAlpha %.2f, %.2f, %.2f, %.2f, %d, 0x%x", level * 2, "",
349                    (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop,
350                    mMultipliedAlpha, flags);
351        }
352    }
353    if (mClipChildren && !mCaching) {
354        ALOGD("%*sClipRect %.2f, %.2f, %.2f, %.2f", level * 2, "", 0.0f, 0.0f,
355                (float) mRight - mLeft, (float) mBottom - mTop);
356    }
357}
358
359void DisplayList::setViewProperties(OpenGLRenderer& renderer, uint32_t level) {
360#if DEBUG_DISPLAYLIST
361    outputViewProperties(level);
362#endif
363    updateMatrix();
364    if (mLeft != 0 || mTop != 0) {
365        renderer.translate(mLeft, mTop);
366    }
367    if (mStaticMatrix) {
368        renderer.concatMatrix(mStaticMatrix);
369    } else if (mAnimationMatrix) {
370        renderer.concatMatrix(mAnimationMatrix);
371    }
372    if (mMatrixFlags != 0) {
373        if (mMatrixFlags == TRANSLATION) {
374            renderer.translate(mTranslationX, mTranslationY);
375        } else {
376            renderer.concatMatrix(mTransformMatrix);
377        }
378    }
379    if (mAlpha < 1 && !mCaching) {
380        if (!mHasOverlappingRendering) {
381            renderer.setAlpha(mAlpha);
382        } else {
383            // TODO: should be able to store the size of a DL at record time and not
384            // have to pass it into this call. In fact, this information might be in the
385            // location/size info that we store with the new native transform data.
386            int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
387            if (mClipChildren) {
388                flags |= SkCanvas::kClipToLayer_SaveFlag;
389            }
390            renderer.saveLayerAlpha(0, 0, mRight - mLeft, mBottom - mTop,
391                    mMultipliedAlpha, flags);
392        }
393    }
394    if (mClipChildren && !mCaching) {
395        renderer.clipRect(0, 0, mRight - mLeft, mBottom - mTop,
396                SkRegion::kIntersect_Op);
397    }
398}
399
400status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level,
401        DeferredDisplayList* deferredList) {
402    status_t drawGlStatus = DrawGlInfo::kStatusDone;
403
404#if DEBUG_DISPLAY_LIST
405    Rect* clipRect = renderer.getClipRect();
406    DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.f, %.0f, %.0f",
407            (level+1)*2, "", this, mName.string(), clipRect->left, clipRect->top,
408            clipRect->right, clipRect->bottom);
409#endif
410
411    renderer.startMark(mName.string());
412
413    int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
414    DISPLAY_LIST_LOGD("%*sSave %d %d", level * 2, "",
415            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
416
417    if (mAlpha < 1 && !mCaching && CC_LIKELY(deferredList)) {
418        // flush before a saveLayerAlpha/setAlpha
419        // TODO: make this cleaner
420        drawGlStatus |= deferredList->flush(renderer, dirty, flags, level);
421    }
422    setViewProperties(renderer, level);
423
424    if (renderer.quickRejectNoScissor(0, 0, mWidth, mHeight)) {
425        DISPLAY_LIST_LOGD("%*sRestoreToCount %d", level * 2, "", restoreTo);
426        renderer.restoreToCount(restoreTo);
427        renderer.endMark();
428        return drawGlStatus;
429    }
430
431    DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
432    int saveCount = renderer.getSaveCount() - 1;
433    for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
434        DisplayListOp *op = mDisplayListData->displayListOps[i];
435#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
436        Caches::getInstance().eventMark(strlen(op->name()), op->name());
437#endif
438
439        if (deferredList) {
440            drawGlStatus |= op->replay(renderer, dirty, flags,
441                    saveCount, level, mCaching, mMultipliedAlpha, *deferredList);
442        } else {
443            drawGlStatus |= op->replay(renderer, dirty, flags,
444                    saveCount, level, mCaching, mMultipliedAlpha);
445        }
446        logBuffer.writeCommand(level, op->name());
447    }
448
449    DISPLAY_LIST_LOGD("%*sRestoreToCount %d", level * 2, "", restoreTo);
450    renderer.restoreToCount(restoreTo);
451    renderer.endMark();
452
453    DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", (level + 1) * 2, "", this, mName.string(),
454            drawGlStatus);
455
456    if (!level && CC_LIKELY(deferredList)) {
457        drawGlStatus |= deferredList->flush(renderer, dirty, flags, level);
458    }
459
460    return drawGlStatus;
461}
462
463}; // namespace uirenderer
464}; // namespace android
465