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