DisplayList.cpp revision c46d07a29e94807e768f8b162ce9f77a88ba6f46
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    mMultipliedAlpha = 255;
237    mHasOverlappingRendering = true;
238    mTranslationX = 0;
239    mTranslationY = 0;
240    mRotation = 0;
241    mRotationX = 0;
242    mRotationY= 0;
243    mScaleX = 1;
244    mScaleY = 1;
245    mPivotX = 0;
246    mPivotY = 0;
247    mCameraDistance = 0;
248    mMatrixDirty = false;
249    mMatrixFlags = 0;
250    mPrevWidth = -1;
251    mPrevHeight = -1;
252    mWidth = 0;
253    mHeight = 0;
254    mPivotExplicitlySet = false;
255    mCaching = false;
256}
257
258size_t DisplayList::getSize() {
259    return mSize;
260}
261
262/**
263 * This function is a simplified version of replay(), where we simply retrieve and log the
264 * display list. This function should remain in sync with the replay() function.
265 */
266void DisplayList::output(uint32_t level) {
267    ALOGD("%*sStart display list (%p, %s, render=%d)", (level - 1) * 2, "", this,
268            mName.string(), isRenderable());
269    ALOGD("%*s%s %d", level * 2, "", "Save",
270            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
271
272    outputViewProperties(level);
273    int flags = DisplayListOp::kOpLogFlag_Recurse;
274    for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
275        mDisplayListData->displayListOps[i]->output(level, flags);
276    }
277
278    ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, mName.string());
279}
280
281float DisplayList::getPivotX() {
282    updateMatrix();
283    return mPivotX;
284}
285
286float DisplayList::getPivotY() {
287    updateMatrix();
288    return mPivotY;
289}
290
291void DisplayList::updateMatrix() {
292    if (mMatrixDirty) {
293        if (!mTransformMatrix) {
294            mTransformMatrix = new SkMatrix();
295        }
296        if (mMatrixFlags == 0 || mMatrixFlags == TRANSLATION) {
297            mTransformMatrix->reset();
298        } else {
299            if (!mPivotExplicitlySet) {
300                if (mWidth != mPrevWidth || mHeight != mPrevHeight) {
301                    mPrevWidth = mWidth;
302                    mPrevHeight = mHeight;
303                    mPivotX = mPrevWidth / 2;
304                    mPivotY = mPrevHeight / 2;
305                }
306            }
307            if ((mMatrixFlags & ROTATION_3D) == 0) {
308                mTransformMatrix->setTranslate(mTranslationX, mTranslationY);
309                mTransformMatrix->preRotate(mRotation, mPivotX, mPivotY);
310                mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY);
311            } else {
312                if (!mTransformCamera) {
313                    mTransformCamera = new Sk3DView();
314                    mTransformMatrix3D = new SkMatrix();
315                }
316                mTransformMatrix->reset();
317                mTransformCamera->save();
318                mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY);
319                mTransformCamera->rotateX(mRotationX);
320                mTransformCamera->rotateY(mRotationY);
321                mTransformCamera->rotateZ(-mRotation);
322                mTransformCamera->getMatrix(mTransformMatrix3D);
323                mTransformMatrix3D->preTranslate(-mPivotX, -mPivotY);
324                mTransformMatrix3D->postTranslate(mPivotX + mTranslationX,
325                        mPivotY + mTranslationY);
326                mTransformMatrix->postConcat(*mTransformMatrix3D);
327                mTransformCamera->restore();
328            }
329        }
330        mMatrixDirty = false;
331    }
332}
333
334void DisplayList::outputViewProperties(const int level) {
335    updateMatrix();
336    if (mLeft != 0 || mTop != 0) {
337        ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", mLeft, mTop);
338    }
339    if (mStaticMatrix) {
340        ALOGD("%*sConcatMatrix (static) %p: " MATRIX_STRING,
341                level * 2, "", mStaticMatrix, MATRIX_ARGS(mStaticMatrix));
342    }
343    if (mAnimationMatrix) {
344        ALOGD("%*sConcatMatrix (animation) %p: " MATRIX_STRING,
345                level * 2, "", mAnimationMatrix, MATRIX_ARGS(mStaticMatrix));
346    }
347    if (mMatrixFlags != 0) {
348        if (mMatrixFlags == TRANSLATION) {
349            ALOGD("%*sTranslate %f, %f", level * 2, "", mTranslationX, mTranslationY);
350        } else {
351            ALOGD("%*sConcatMatrix %p: " MATRIX_STRING,
352                    level * 2, "", mTransformMatrix, MATRIX_ARGS(mTransformMatrix));
353        }
354    }
355    if (mAlpha < 1 && !mCaching) {
356        if (!mHasOverlappingRendering) {
357            ALOGD("%*sSetAlpha %.2f", level * 2, "", mAlpha);
358        } else {
359            int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
360            if (mClipChildren) {
361                flags |= SkCanvas::kClipToLayer_SaveFlag;
362            }
363            ALOGD("%*sSaveLayerAlpha %.2f, %.2f, %.2f, %.2f, %d, 0x%x", level * 2, "",
364                    (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop,
365                    mMultipliedAlpha, flags);
366        }
367    }
368    if (mClipChildren && !mCaching) {
369        ALOGD("%*sClipRect %.2f, %.2f, %.2f, %.2f", level * 2, "", 0.0f, 0.0f,
370                (float) mRight - mLeft, (float) mBottom - mTop);
371    }
372}
373
374/*
375 * For property operations, we pass a savecount of 0, since the operations aren't part of the
376 * displaylist, and thus don't have to compensate for the record-time/playback-time discrepancy in
377 * base saveCount (i.e., how RestoreToCount uses saveCount + mCount)
378 */
379#define PROPERTY_SAVECOUNT 0
380
381template <class T>
382void DisplayList::setViewProperties(OpenGLRenderer& renderer, T& handler,
383        const int level) {
384#if DEBUG_DISPLAY_LIST
385    outputViewProperties(level);
386#endif
387    updateMatrix();
388    if (mLeft != 0 || mTop != 0) {
389        renderer.translate(mLeft, mTop);
390    }
391    if (mStaticMatrix) {
392        renderer.concatMatrix(mStaticMatrix);
393    } else if (mAnimationMatrix) {
394        renderer.concatMatrix(mAnimationMatrix);
395    }
396    if (mMatrixFlags != 0) {
397        if (mMatrixFlags == TRANSLATION) {
398            renderer.translate(mTranslationX, mTranslationY);
399        } else {
400            renderer.concatMatrix(mTransformMatrix);
401        }
402    }
403    if (mAlpha < 1 && !mCaching) {
404        if (!mHasOverlappingRendering) {
405            renderer.setAlpha(mAlpha);
406        } else {
407            // TODO: should be able to store the size of a DL at record time and not
408            // have to pass it into this call. In fact, this information might be in the
409            // location/size info that we store with the new native transform data.
410            int saveFlags = SkCanvas::kHasAlphaLayer_SaveFlag;
411            if (mClipChildren) {
412                saveFlags |= SkCanvas::kClipToLayer_SaveFlag;
413            }
414            handler(mSaveLayerOp->reinit(0, 0, mRight - mLeft, mBottom - mTop,
415                    mMultipliedAlpha, SkXfermode::kSrcOver_Mode, saveFlags), PROPERTY_SAVECOUNT);
416        }
417    }
418    if (mClipChildren && !mCaching) {
419        handler(mClipRectOp->reinit(0, 0, mRight - mLeft, mBottom - mTop, SkRegion::kIntersect_Op),
420                PROPERTY_SAVECOUNT);
421    }
422}
423
424class DeferOperationHandler {
425public:
426    DeferOperationHandler(DeferStateStruct& deferStruct, int multipliedAlpha, int level)
427        : mDeferStruct(deferStruct), mMultipliedAlpha(multipliedAlpha), mLevel(level) {}
428    inline void operator()(DisplayListOp* operation, int saveCount) {
429        operation->defer(mDeferStruct, saveCount, mLevel, mMultipliedAlpha);
430    }
431private:
432    DeferStateStruct& mDeferStruct;
433    const int mMultipliedAlpha;
434    const int mLevel;
435};
436
437void DisplayList::defer(DeferStateStruct& deferStruct, const int level) {
438    DeferOperationHandler handler(deferStruct, mCaching ? mMultipliedAlpha : -1, level);
439    iterate<DeferOperationHandler>(deferStruct.mRenderer, handler, level);
440}
441
442class ReplayOperationHandler {
443public:
444    ReplayOperationHandler(ReplayStateStruct& replayStruct, int multipliedAlpha, int level)
445        : mReplayStruct(replayStruct), mMultipliedAlpha(multipliedAlpha), mLevel(level) {}
446    inline void operator()(DisplayListOp* operation, int saveCount) {
447#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
448        replayStruct.mRenderer.eventMark(operation->name());
449#endif
450        operation->replay(mReplayStruct, saveCount, mLevel, mMultipliedAlpha);
451    }
452private:
453    ReplayStateStruct& mReplayStruct;
454    const int mMultipliedAlpha;
455    const int mLevel;
456};
457
458void DisplayList::replay(ReplayStateStruct& replayStruct, const int level) {
459    ReplayOperationHandler handler(replayStruct, mCaching ? mMultipliedAlpha : -1, level);
460
461    replayStruct.mRenderer.startMark(mName.string());
462    iterate<ReplayOperationHandler>(replayStruct.mRenderer, handler, level);
463    replayStruct.mRenderer.endMark();
464
465    DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", level * 2, "", this, mName.string(),
466            replayStruct.mDrawGlStatus);
467}
468
469/**
470 * This function serves both defer and replay modes, and will organize the displayList's component
471 * operations for a single frame:
472 *
473 * Every 'simple' operation that affects just the matrix and alpha (or other factors of
474 * DeferredDisplayState) may be issued directly to the renderer, but complex operations (with custom
475 * defer logic) and operations in displayListOps are issued through the 'handler' which handles the
476 * defer vs replay logic, per operation
477 */
478template <class T>
479void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level) {
480    if (mSize == 0 || mAlpha <= 0) {
481        DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, mName.string());
482        return;
483    }
484
485#if DEBUG_DISPLAY_LIST
486    Rect* clipRect = renderer.getClipRect();
487    DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.f, %.0f, %.0f",
488            level * 2, "", this, mName.string(), clipRect->left, clipRect->top,
489            clipRect->right, clipRect->bottom);
490#endif
491
492    int restoreTo = renderer.getSaveCount();
493    handler(mSaveOp->reinit(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag),
494            PROPERTY_SAVECOUNT);
495
496    DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "",
497            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
498
499    setViewProperties<T>(renderer, handler, level + 1);
500
501    if (renderer.quickRejectNoScissor(0, 0, mWidth, mHeight)) {
502        DISPLAY_LIST_LOGD("%*sRestoreToCount %d", level * 2, "", restoreTo);
503        handler(mRestoreToCountOp->reinit(restoreTo), PROPERTY_SAVECOUNT);
504        return;
505    }
506
507    DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
508    int saveCount = renderer.getSaveCount() - 1;
509    for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
510        DisplayListOp *op = mDisplayListData->displayListOps[i];
511
512        handler(op, saveCount);
513        logBuffer.writeCommand(level, op->name());
514    }
515
516    DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
517    handler(mRestoreToCountOp->reinit(restoreTo), PROPERTY_SAVECOUNT);
518    renderer.restoreToCount(restoreTo);
519}
520
521}; // namespace uirenderer
522}; // namespace android
523