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