blob: 8aac6288cf7b096da6c55d1993529ff18cb6a01b [file] [log] [blame]
Chris Craik0776a602013-02-14 15:36:01 -08001/*
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
Chris Craikc3566d02013-02-04 16:16:33 -080017#include "Debug.h"
Chris Craik0776a602013-02-14 15:36:01 -080018#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
Chris Craikc3566d02013-02-04 16:16:33 -0800390status_t DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level,
391 DeferredDisplayList* deferredList) {
Chris Craik0776a602013-02-14 15:36:01 -0800392 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);
Chris Craikc3566d02013-02-04 16:16:33 -0800406
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 }
Chris Craik0776a602013-02-14 15:36:01 -0800412 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
Chris Craikc3566d02013-02-04 16:16:33 -0800429 if (deferredList) {
430 drawGlStatus |= op->replay(renderer, dirty, flags,
431 saveCount, level, mCaching, mMultipliedAlpha, *deferredList);
432 } else {
433 drawGlStatus |= op->replay(renderer, dirty, flags,
434 saveCount, level, mCaching, mMultipliedAlpha);
435 }
Chris Craik0776a602013-02-14 15:36:01 -0800436 logBuffer.writeCommand(level, op->name());
437 }
438
439 DISPLAY_LIST_LOGD("%*sRestoreToCount %d", level * 2, "", restoreTo);
440 renderer.restoreToCount(restoreTo);
441 renderer.endMark();
442
443 DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", (level + 1) * 2, "", this, mName.string(),
444 drawGlStatus);
Chris Craikc3566d02013-02-04 16:16:33 -0800445
446 if (!level && CC_LIKELY(deferredList)) {
447 drawGlStatus |= deferredList->flush(renderer, dirty, flags, level);
448 }
449
Chris Craik0776a602013-02-14 15:36:01 -0800450 return drawGlStatus;
451}
452
453}; // namespace uirenderer
454}; // namespace android