blob: fd3dae7dfd71557bcbe85ca93bf09426ac8b0f5a [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 Craikf57776b2013-10-25 18:30:17 -070017#define ATRACE_TAG ATRACE_TAG_VIEW
18
Romain Guyc46d07a2013-03-15 19:06:39 -070019#include <SkCanvas.h>
Chris Craik9f68c092014-01-10 10:30:57 -080020#include <algorithm>
Romain Guyc46d07a2013-03-15 19:06:39 -070021
Chris Craikf57776b2013-10-25 18:30:17 -070022#include <utils/Trace.h>
23
Chris Craikc3566d02013-02-04 16:16:33 -080024#include "Debug.h"
Chris Craik0776a602013-02-14 15:36:01 -080025#include "DisplayList.h"
26#include "DisplayListOp.h"
27#include "DisplayListLogBuffer.h"
28
29namespace android {
30namespace uirenderer {
31
32void DisplayList::outputLogBuffer(int fd) {
33 DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
34 if (logBuffer.isEmpty()) {
35 return;
36 }
37
38 FILE *file = fdopen(fd, "a");
39
40 fprintf(file, "\nRecent DisplayList operations\n");
41 logBuffer.outputCommands(file);
42
43 String8 cachesLog;
44 Caches::getInstance().dumpMemoryUsage(cachesLog);
45 fprintf(file, "\nCaches:\n%s", cachesLog.string());
46 fprintf(file, "\n");
47
48 fflush(file);
49}
50
51DisplayList::DisplayList(const DisplayListRenderer& recorder) :
Chris Craik9846de62013-06-12 16:23:00 -070052 mDestroyed(false), mTransformMatrix(NULL), mTransformCamera(NULL), mTransformMatrix3D(NULL),
Chris Craik0776a602013-02-14 15:36:01 -080053 mStaticMatrix(NULL), mAnimationMatrix(NULL) {
54
55 initFromDisplayListRenderer(recorder);
56}
57
58DisplayList::~DisplayList() {
Chris Craik9846de62013-06-12 16:23:00 -070059 mDestroyed = true;
Chris Craik0776a602013-02-14 15:36:01 -080060 clearResources();
61}
62
63void DisplayList::destroyDisplayListDeferred(DisplayList* displayList) {
64 if (displayList) {
65 DISPLAY_LIST_LOGD("Deferring display list destruction");
66 Caches::getInstance().deleteDisplayListDeferred(displayList);
67 }
68}
69
70void DisplayList::clearResources() {
71 mDisplayListData = NULL;
Chris Craikff785832013-03-08 13:12:16 -080072
Chris Craik0776a602013-02-14 15:36:01 -080073 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++) {
Chris Craikd218a922014-01-02 17:13:34 -080094 const SkBitmap* bitmap = mOwnedBitmapResources.itemAt(i);
Chris Craik0776a602013-02-14 15:36:01 -080095 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
Romain Guye3b0a012013-06-26 15:45:41 -0700103 for (size_t i = 0; i < mPatchResources.size(); i++) {
104 caches.resourceCache.decrementRefcountLocked(mPatchResources.itemAt(i));
105 }
106
Chris Craik0776a602013-02-14 15:36:01 -0800107 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++) {
Romain Guyc46d07a2013-03-15 19:06:39 -0700131 delete mPaths.itemAt(i);
Chris Craik0776a602013-02-14 15:36:01 -0800132 }
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();
Romain Guye3b0a012013-06-26 15:45:41 -0700141 mPatchResources.clear();
Chris Craik0776a602013-02-14 15:36:01 -0800142 mShaders.clear();
143 mSourcePaths.clear();
144 mPaints.clear();
145 mRegions.clear();
146 mPaths.clear();
147 mMatrices.clear();
148 mLayers.clear();
149}
150
151void DisplayList::reset() {
152 clearResources();
153 init();
154}
155
156void 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 mFunctorCount = recorder.getFunctorCount();
172
173 Caches& caches = Caches::getInstance();
174 caches.registerFunctors(mFunctorCount);
175 caches.resourceCache.lock();
176
Chris Craikd218a922014-01-02 17:13:34 -0800177 const Vector<const SkBitmap*>& bitmapResources = recorder.getBitmapResources();
Chris Craik0776a602013-02-14 15:36:01 -0800178 for (size_t i = 0; i < bitmapResources.size(); i++) {
Chris Craikd218a922014-01-02 17:13:34 -0800179 const SkBitmap* resource = bitmapResources.itemAt(i);
Chris Craik0776a602013-02-14 15:36:01 -0800180 mBitmapResources.add(resource);
181 caches.resourceCache.incrementRefcountLocked(resource);
182 }
183
Chris Craikd218a922014-01-02 17:13:34 -0800184 const Vector<const SkBitmap*>& ownedBitmapResources = recorder.getOwnedBitmapResources();
Chris Craik0776a602013-02-14 15:36:01 -0800185 for (size_t i = 0; i < ownedBitmapResources.size(); i++) {
Chris Craikd218a922014-01-02 17:13:34 -0800186 const SkBitmap* resource = ownedBitmapResources.itemAt(i);
Chris Craik0776a602013-02-14 15:36:01 -0800187 mOwnedBitmapResources.add(resource);
188 caches.resourceCache.incrementRefcountLocked(resource);
189 }
190
191 const Vector<SkiaColorFilter*>& filterResources = recorder.getFilterResources();
192 for (size_t i = 0; i < filterResources.size(); i++) {
193 SkiaColorFilter* resource = filterResources.itemAt(i);
194 mFilterResources.add(resource);
195 caches.resourceCache.incrementRefcountLocked(resource);
196 }
197
Chris Craikd218a922014-01-02 17:13:34 -0800198 const Vector<const Res_png_9patch*>& patchResources = recorder.getPatchResources();
Romain Guye3b0a012013-06-26 15:45:41 -0700199 for (size_t i = 0; i < patchResources.size(); i++) {
Chris Craikd218a922014-01-02 17:13:34 -0800200 const Res_png_9patch* resource = patchResources.itemAt(i);
Romain Guye3b0a012013-06-26 15:45:41 -0700201 mPatchResources.add(resource);
202 caches.resourceCache.incrementRefcountLocked(resource);
203 }
204
Chris Craik0776a602013-02-14 15:36:01 -0800205 const Vector<SkiaShader*>& shaders = recorder.getShaders();
206 for (size_t i = 0; i < shaders.size(); i++) {
207 SkiaShader* resource = shaders.itemAt(i);
208 mShaders.add(resource);
209 caches.resourceCache.incrementRefcountLocked(resource);
210 }
211
Chris Craikd218a922014-01-02 17:13:34 -0800212 const SortedVector<const SkPath*>& sourcePaths = recorder.getSourcePaths();
Chris Craik0776a602013-02-14 15:36:01 -0800213 for (size_t i = 0; i < sourcePaths.size(); i++) {
214 mSourcePaths.add(sourcePaths.itemAt(i));
215 caches.resourceCache.incrementRefcountLocked(sourcePaths.itemAt(i));
216 }
217
218 const Vector<Layer*>& layers = recorder.getLayers();
219 for (size_t i = 0; i < layers.size(); i++) {
220 mLayers.add(layers.itemAt(i));
221 caches.resourceCache.incrementRefcountLocked(layers.itemAt(i));
222 }
223
224 caches.resourceCache.unlock();
225
226 mPaints.appendVector(recorder.getPaints());
227 mRegions.appendVector(recorder.getRegions());
228 mPaths.appendVector(recorder.getPaths());
229 mMatrices.appendVector(recorder.getMatrices());
230}
231
232void DisplayList::init() {
233 mSize = 0;
234 mIsRenderable = true;
235 mFunctorCount = 0;
236 mLeft = 0;
237 mTop = 0;
238 mRight = 0;
239 mBottom = 0;
Chet Haasedd671592013-04-19 14:54:34 -0700240 mClipToBounds = true;
Chris Craik6657a6c2014-01-26 11:30:58 -0800241 mIsolatedZVolume = true;
242 mProjectBackwards = false;
Chris Craika2fe7af2014-01-28 17:25:06 -0800243 mOutline.rewind();
Chris Craik0776a602013-02-14 15:36:01 -0800244 mAlpha = 1;
Chris Craik0776a602013-02-14 15:36:01 -0800245 mHasOverlappingRendering = true;
246 mTranslationX = 0;
247 mTranslationY = 0;
Chris Craikf57776b2013-10-25 18:30:17 -0700248 mTranslationZ = 0;
Chris Craik0776a602013-02-14 15:36:01 -0800249 mRotation = 0;
250 mRotationX = 0;
251 mRotationY= 0;
252 mScaleX = 1;
253 mScaleY = 1;
254 mPivotX = 0;
255 mPivotY = 0;
256 mCameraDistance = 0;
257 mMatrixDirty = false;
258 mMatrixFlags = 0;
259 mPrevWidth = -1;
260 mPrevHeight = -1;
261 mWidth = 0;
262 mHeight = 0;
263 mPivotExplicitlySet = false;
264 mCaching = false;
265}
266
267size_t DisplayList::getSize() {
268 return mSize;
269}
270
271/**
272 * This function is a simplified version of replay(), where we simply retrieve and log the
273 * display list. This function should remain in sync with the replay() function.
274 */
275void DisplayList::output(uint32_t level) {
Romain Guy7031ff62013-02-22 11:48:16 -0800276 ALOGD("%*sStart display list (%p, %s, render=%d)", (level - 1) * 2, "", this,
Chris Craik0776a602013-02-14 15:36:01 -0800277 mName.string(), isRenderable());
Romain Guy7031ff62013-02-22 11:48:16 -0800278 ALOGD("%*s%s %d", level * 2, "", "Save",
279 SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
Chris Craik0776a602013-02-14 15:36:01 -0800280
Chris Craik0776a602013-02-14 15:36:01 -0800281 outputViewProperties(level);
282 int flags = DisplayListOp::kOpLogFlag_Recurse;
283 for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
284 mDisplayListData->displayListOps[i]->output(level, flags);
285 }
Romain Guy7031ff62013-02-22 11:48:16 -0800286
287 ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, mName.string());
Chris Craik0776a602013-02-14 15:36:01 -0800288}
289
Romain Guy52036b12013-02-14 18:03:37 -0800290float DisplayList::getPivotX() {
291 updateMatrix();
292 return mPivotX;
293}
294
295float DisplayList::getPivotY() {
296 updateMatrix();
297 return mPivotY;
298}
299
Chris Craik0776a602013-02-14 15:36:01 -0800300void DisplayList::updateMatrix() {
301 if (mMatrixDirty) {
302 if (!mTransformMatrix) {
303 mTransformMatrix = new SkMatrix();
304 }
305 if (mMatrixFlags == 0 || mMatrixFlags == TRANSLATION) {
306 mTransformMatrix->reset();
307 } else {
308 if (!mPivotExplicitlySet) {
309 if (mWidth != mPrevWidth || mHeight != mPrevHeight) {
310 mPrevWidth = mWidth;
311 mPrevHeight = mHeight;
Chet Haase259b6962013-05-03 15:25:33 -0700312 mPivotX = mPrevWidth / 2.0f;
313 mPivotY = mPrevHeight / 2.0f;
Chris Craik0776a602013-02-14 15:36:01 -0800314 }
315 }
Chris Craikba9b6132013-12-15 17:10:19 -0800316 if (!Caches::getInstance().propertyEnable3d && (mMatrixFlags & ROTATION_3D) == 0) {
Chris Craik0776a602013-02-14 15:36:01 -0800317 mTransformMatrix->setTranslate(mTranslationX, mTranslationY);
318 mTransformMatrix->preRotate(mRotation, mPivotX, mPivotY);
319 mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY);
320 } else {
Chris Craikba9b6132013-12-15 17:10:19 -0800321 if (Caches::getInstance().propertyEnable3d) {
Chris Craikf57776b2013-10-25 18:30:17 -0700322 mTransform.loadTranslate(mPivotX + mTranslationX, mPivotY + mTranslationY,
323 mTranslationZ);
324 mTransform.rotate(mRotationX, 1, 0, 0);
325 mTransform.rotate(mRotationY, 0, 1, 0);
326 mTransform.rotate(mRotation, 0, 0, 1);
327 mTransform.scale(mScaleX, mScaleY, 1);
328 mTransform.translate(-mPivotX, -mPivotY);
329 } else {
330 /* TODO: support this old transform approach, based on API level */
331 if (!mTransformCamera) {
332 mTransformCamera = new Sk3DView();
333 mTransformMatrix3D = new SkMatrix();
334 }
335 mTransformMatrix->reset();
336 mTransformCamera->save();
337 mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY);
338 mTransformCamera->rotateX(mRotationX);
339 mTransformCamera->rotateY(mRotationY);
340 mTransformCamera->rotateZ(-mRotation);
341 mTransformCamera->getMatrix(mTransformMatrix3D);
342 mTransformMatrix3D->preTranslate(-mPivotX, -mPivotY);
343 mTransformMatrix3D->postTranslate(mPivotX + mTranslationX,
344 mPivotY + mTranslationY);
345 mTransformMatrix->postConcat(*mTransformMatrix3D);
346 mTransformCamera->restore();
Chris Craik0776a602013-02-14 15:36:01 -0800347 }
Chris Craik0776a602013-02-14 15:36:01 -0800348 }
349 }
350 mMatrixDirty = false;
351 }
352}
353
Chris Craikff785832013-03-08 13:12:16 -0800354void DisplayList::outputViewProperties(const int level) {
Chris Craik0776a602013-02-14 15:36:01 -0800355 updateMatrix();
356 if (mLeft != 0 || mTop != 0) {
357 ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", mLeft, mTop);
358 }
359 if (mStaticMatrix) {
360 ALOGD("%*sConcatMatrix (static) %p: " MATRIX_STRING,
361 level * 2, "", mStaticMatrix, MATRIX_ARGS(mStaticMatrix));
362 }
363 if (mAnimationMatrix) {
364 ALOGD("%*sConcatMatrix (animation) %p: " MATRIX_STRING,
Chris Craik66063ae2013-09-05 16:11:18 -0700365 level * 2, "", mAnimationMatrix, MATRIX_ARGS(mAnimationMatrix));
Chris Craik0776a602013-02-14 15:36:01 -0800366 }
367 if (mMatrixFlags != 0) {
368 if (mMatrixFlags == TRANSLATION) {
369 ALOGD("%*sTranslate %f, %f", level * 2, "", mTranslationX, mTranslationY);
370 } else {
371 ALOGD("%*sConcatMatrix %p: " MATRIX_STRING,
372 level * 2, "", mTransformMatrix, MATRIX_ARGS(mTransformMatrix));
373 }
374 }
Chris Craik39a908c2013-06-13 14:39:01 -0700375
Romain Guy1de466f2013-09-12 16:09:19 -0700376 bool clipToBoundsNeeded = mCaching ? false : mClipToBounds;
Chris Craik5f803622013-03-21 14:39:04 -0700377 if (mAlpha < 1) {
Chris Craik16ecda52013-03-29 10:59:59 -0700378 if (mCaching) {
379 ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mAlpha);
380 } else if (!mHasOverlappingRendering) {
Chris Craik5f803622013-03-21 14:39:04 -0700381 ALOGD("%*sScaleAlpha %.2f", level * 2, "", mAlpha);
Chris Craik0776a602013-02-14 15:36:01 -0800382 } else {
383 int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
Chris Craik39a908c2013-06-13 14:39:01 -0700384 if (clipToBoundsNeeded) {
Chris Craik0776a602013-02-14 15:36:01 -0800385 flags |= SkCanvas::kClipToLayer_SaveFlag;
Chris Craik39a908c2013-06-13 14:39:01 -0700386 clipToBoundsNeeded = false; // clipping done by save layer
Chris Craik0776a602013-02-14 15:36:01 -0800387 }
388 ALOGD("%*sSaveLayerAlpha %.2f, %.2f, %.2f, %.2f, %d, 0x%x", level * 2, "",
389 (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop,
Chris Craika08f95c2013-03-15 17:24:33 -0700390 (int)(mAlpha * 255), flags);
Chris Craik0776a602013-02-14 15:36:01 -0800391 }
392 }
Chris Craik39a908c2013-06-13 14:39:01 -0700393 if (clipToBoundsNeeded) {
Chris Craik0776a602013-02-14 15:36:01 -0800394 ALOGD("%*sClipRect %.2f, %.2f, %.2f, %.2f", level * 2, "", 0.0f, 0.0f,
395 (float) mRight - mLeft, (float) mBottom - mTop);
396 }
397}
398
Chris Craikff785832013-03-08 13:12:16 -0800399/*
400 * For property operations, we pass a savecount of 0, since the operations aren't part of the
401 * displaylist, and thus don't have to compensate for the record-time/playback-time discrepancy in
402 * base saveCount (i.e., how RestoreToCount uses saveCount + mCount)
403 */
404#define PROPERTY_SAVECOUNT 0
405
406template <class T>
407void DisplayList::setViewProperties(OpenGLRenderer& renderer, T& handler,
408 const int level) {
409#if DEBUG_DISPLAY_LIST
Chris Craik0776a602013-02-14 15:36:01 -0800410 outputViewProperties(level);
411#endif
412 updateMatrix();
413 if (mLeft != 0 || mTop != 0) {
414 renderer.translate(mLeft, mTop);
415 }
416 if (mStaticMatrix) {
417 renderer.concatMatrix(mStaticMatrix);
418 } else if (mAnimationMatrix) {
419 renderer.concatMatrix(mAnimationMatrix);
420 }
421 if (mMatrixFlags != 0) {
Chris Craikcf8d9d42014-01-16 14:48:54 -0800422 if (Caches::getInstance().propertyEnable3d) {
423 if (mMatrixFlags == TRANSLATION) {
424 renderer.translate(mTranslationX, mTranslationY, mTranslationZ);
425 } else {
Chris Craikba9b6132013-12-15 17:10:19 -0800426 renderer.concatMatrix(mTransform);
Chris Craikcf8d9d42014-01-16 14:48:54 -0800427 }
428 } else {
429 // avoid setting translationZ, use SkMatrix
430 if (mMatrixFlags == TRANSLATION) {
431 renderer.translate(mTranslationX, mTranslationY, 0);
Chris Craikba9b6132013-12-15 17:10:19 -0800432 } else {
433 renderer.concatMatrix(mTransformMatrix);
434 }
Chris Craik0776a602013-02-14 15:36:01 -0800435 }
436 }
Romain Guy1de466f2013-09-12 16:09:19 -0700437 bool clipToBoundsNeeded = mCaching ? false : mClipToBounds;
Chris Craika08f95c2013-03-15 17:24:33 -0700438 if (mAlpha < 1) {
Chris Craik16ecda52013-03-29 10:59:59 -0700439 if (mCaching) {
440 renderer.setOverrideLayerAlpha(mAlpha);
441 } else if (!mHasOverlappingRendering) {
Chris Craika08f95c2013-03-15 17:24:33 -0700442 renderer.scaleAlpha(mAlpha);
Chris Craik0776a602013-02-14 15:36:01 -0800443 } else {
444 // TODO: should be able to store the size of a DL at record time and not
445 // have to pass it into this call. In fact, this information might be in the
446 // location/size info that we store with the new native transform data.
Chris Craikff785832013-03-08 13:12:16 -0800447 int saveFlags = SkCanvas::kHasAlphaLayer_SaveFlag;
Chris Craik39a908c2013-06-13 14:39:01 -0700448 if (clipToBoundsNeeded) {
Chris Craikff785832013-03-08 13:12:16 -0800449 saveFlags |= SkCanvas::kClipToLayer_SaveFlag;
Chris Craik39a908c2013-06-13 14:39:01 -0700450 clipToBoundsNeeded = false; // clipping done by saveLayer
Chris Craik0776a602013-02-14 15:36:01 -0800451 }
Chris Craikf57776b2013-10-25 18:30:17 -0700452
453 SaveLayerOp* op = new (handler.allocator()) SaveLayerOp(
454 0, 0, mRight - mLeft, mBottom - mTop,
455 mAlpha * 255, SkXfermode::kSrcOver_Mode, saveFlags);
456 handler(op, PROPERTY_SAVECOUNT, mClipToBounds);
Chris Craik0776a602013-02-14 15:36:01 -0800457 }
458 }
Chris Craik39a908c2013-06-13 14:39:01 -0700459 if (clipToBoundsNeeded) {
Chris Craikf57776b2013-10-25 18:30:17 -0700460 ClipRectOp* op = new (handler.allocator()) ClipRectOp(0, 0,
461 mRight - mLeft, mBottom - mTop, SkRegion::kIntersect_Op);
462 handler(op, PROPERTY_SAVECOUNT, mClipToBounds);
463 }
464}
465
466/**
467 * Apply property-based transformations to input matrix
468 */
469void DisplayList::applyViewPropertyTransforms(mat4& matrix) {
470 if (mLeft != 0 || mTop != 0) {
471 matrix.translate(mLeft, mTop);
472 }
473 if (mStaticMatrix) {
474 mat4 stat(*mStaticMatrix);
475 matrix.multiply(stat);
476 } else if (mAnimationMatrix) {
477 mat4 anim(*mAnimationMatrix);
478 matrix.multiply(anim);
479 }
480 if (mMatrixFlags != 0) {
Chris Craikf533e942014-01-14 22:35:37 -0800481 updateMatrix();
Chris Craikf57776b2013-10-25 18:30:17 -0700482 if (mMatrixFlags == TRANSLATION) {
483 matrix.translate(mTranslationX, mTranslationY, mTranslationZ);
484 } else {
Chris Craikba9b6132013-12-15 17:10:19 -0800485 if (Caches::getInstance().propertyEnable3d) {
486 matrix.multiply(mTransform);
487 } else {
488 mat4 temp(*mTransformMatrix);
489 matrix.multiply(temp);
490 }
Chris Craikf57776b2013-10-25 18:30:17 -0700491 }
492 }
493}
494
495/**
496 * Organizes the DisplayList hierarchy to prepare for Z-based draw order.
497 *
498 * This should be called before a call to defer() or drawDisplayList()
499 *
500 * Each DisplayList that serves as a 3d root builds its list of composited children,
501 * which are flagged to not draw in the standard draw loop.
502 */
503void DisplayList::computeOrdering() {
504 ATRACE_CALL();
Chris Craikbb615a62014-01-24 13:22:35 -0800505 m3dNodes.clear();
506 mProjectedNodes.clear();
Chris Craik8b62cda2013-12-17 15:07:47 -0800507
Chris Craikbb615a62014-01-24 13:22:35 -0800508 // TODO: create temporary DDLOp and call computeOrderingImpl on top DisplayList so that
509 // transform properties are applied correctly to top level children
510 if (mDisplayListData == NULL) return;
Chris Craikf57776b2013-10-25 18:30:17 -0700511 for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) {
512 DrawDisplayListOp* childOp = mDisplayListData->children[i];
Chris Craikf533e942014-01-14 22:35:37 -0800513 childOp->mDisplayList->computeOrderingImpl(childOp,
514 &m3dNodes, &mat4::identity(),
Chris Craik3783e702014-01-27 14:26:14 -0800515 &mProjectedNodes, &mat4::identity());
Chris Craikf57776b2013-10-25 18:30:17 -0700516 }
517}
518
519void DisplayList::computeOrderingImpl(
520 DrawDisplayListOp* opState,
Chris Craik9f68c092014-01-10 10:30:57 -0800521 Vector<ZDrawDisplayListOpPair>* compositedChildrenOf3dRoot,
Chris Craikf533e942014-01-14 22:35:37 -0800522 const mat4* transformFrom3dRoot,
523 Vector<DrawDisplayListOp*>* compositedChildrenOfProjectionSurface,
Chris Craik3783e702014-01-27 14:26:14 -0800524 const mat4* transformFromProjectionSurface) {
Chris Craikbb615a62014-01-24 13:22:35 -0800525 m3dNodes.clear();
526 mProjectedNodes.clear();
527
Chris Craikf57776b2013-10-25 18:30:17 -0700528 // TODO: should avoid this calculation in most cases
Chris Craikf533e942014-01-14 22:35:37 -0800529 // TODO: just calculate single matrix, down to all leaf composited elements
530 Matrix4 localTransformFrom3dRoot(*transformFrom3dRoot);
531 localTransformFrom3dRoot.multiply(opState->mTransformFromParent);
532 Matrix4 localTransformFromProjectionSurface(*transformFromProjectionSurface);
533 localTransformFromProjectionSurface.multiply(opState->mTransformFromParent);
Chris Craikf57776b2013-10-25 18:30:17 -0700534
Chris Craikf533e942014-01-14 22:35:37 -0800535 if (mTranslationZ != 0.0f) { // TODO: other signals for 3d compositing, such as custom matrix4
536 // composited 3d layer, flag for out of order draw and save matrix...
Chris Craikf57776b2013-10-25 18:30:17 -0700537 opState->mSkipInOrderDraw = true;
Chris Craikf533e942014-01-14 22:35:37 -0800538 opState->mTransformFromCompositingAncestor.load(localTransformFrom3dRoot);
Chris Craikf57776b2013-10-25 18:30:17 -0700539
Chris Craik9f68c092014-01-10 10:30:57 -0800540 // ... and insert into current 3d root, keyed with pivot z for later sorting
Chris Craikf57776b2013-10-25 18:30:17 -0700541 Vector3 pivot(mPivotX, mPivotY, 0.0f);
Chris Craikf533e942014-01-14 22:35:37 -0800542 mat4 totalTransform(localTransformFrom3dRoot);
Chris Craikf57776b2013-10-25 18:30:17 -0700543 applyViewPropertyTransforms(totalTransform);
544 totalTransform.mapPoint3d(pivot);
Chris Craik9f68c092014-01-10 10:30:57 -0800545 compositedChildrenOf3dRoot->add(ZDrawDisplayListOpPair(pivot.z, opState));
Chris Craik6657a6c2014-01-26 11:30:58 -0800546 } else if (mProjectBackwards) {
Chris Craikf533e942014-01-14 22:35:37 -0800547 // composited projectee, flag for out of order draw, save matrix, and store in proj surface
548 opState->mSkipInOrderDraw = true;
549 opState->mTransformFromCompositingAncestor.load(localTransformFromProjectionSurface);
550 compositedChildrenOfProjectionSurface->add(opState);
Chris Craikf57776b2013-10-25 18:30:17 -0700551 } else {
552 // standard in order draw
553 opState->mSkipInOrderDraw = false;
554 }
555
Chris Craik6657a6c2014-01-26 11:30:58 -0800556 if (mIsolatedZVolume) {
Chris Craikf533e942014-01-14 22:35:37 -0800557 // create a new 3d space for descendents by collecting them
Chris Craikf57776b2013-10-25 18:30:17 -0700558 compositedChildrenOf3dRoot = &m3dNodes;
559 transformFrom3dRoot = &mat4::identity();
560 } else {
Chris Craikf533e942014-01-14 22:35:37 -0800561 applyViewPropertyTransforms(localTransformFrom3dRoot);
562 transformFrom3dRoot = &localTransformFrom3dRoot;
563 }
564
Chris Craikf533e942014-01-14 22:35:37 -0800565 if (mDisplayListData != NULL && mDisplayListData->projectionIndex >= 0) {
566 // create a new projection surface for descendents by collecting them
567 compositedChildrenOfProjectionSurface = &mProjectedNodes;
568 transformFromProjectionSurface = &mat4::identity();
569 } else {
570 applyViewPropertyTransforms(localTransformFromProjectionSurface);
571 transformFromProjectionSurface = &localTransformFromProjectionSurface;
Chris Craikf57776b2013-10-25 18:30:17 -0700572 }
573
Chris Craik8b62cda2013-12-17 15:07:47 -0800574 if (mDisplayListData != NULL && mDisplayListData->children.size() > 0) {
Chris Craikf57776b2013-10-25 18:30:17 -0700575 for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) {
576 DrawDisplayListOp* childOp = mDisplayListData->children[i];
577 childOp->mDisplayList->computeOrderingImpl(childOp,
Chris Craikf533e942014-01-14 22:35:37 -0800578 compositedChildrenOf3dRoot, transformFrom3dRoot,
Chris Craik3783e702014-01-27 14:26:14 -0800579 compositedChildrenOfProjectionSurface, transformFromProjectionSurface);
Chris Craikf57776b2013-10-25 18:30:17 -0700580 }
Chris Craik0776a602013-02-14 15:36:01 -0800581 }
582}
583
Chris Craikff785832013-03-08 13:12:16 -0800584class DeferOperationHandler {
585public:
Chris Craika08f95c2013-03-15 17:24:33 -0700586 DeferOperationHandler(DeferStateStruct& deferStruct, int level)
587 : mDeferStruct(deferStruct), mLevel(level) {}
Chet Haasedd671592013-04-19 14:54:34 -0700588 inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) {
589 operation->defer(mDeferStruct, saveCount, mLevel, clipToBounds);
Chris Craikff785832013-03-08 13:12:16 -0800590 }
Chris Craikf57776b2013-10-25 18:30:17 -0700591 inline LinearAllocator& allocator() { return *(mDeferStruct.mAllocator); }
592
Chris Craikff785832013-03-08 13:12:16 -0800593private:
594 DeferStateStruct& mDeferStruct;
Chris Craikff785832013-03-08 13:12:16 -0800595 const int mLevel;
596};
597
598void DisplayList::defer(DeferStateStruct& deferStruct, const int level) {
Chris Craika08f95c2013-03-15 17:24:33 -0700599 DeferOperationHandler handler(deferStruct, level);
Chris Craikff785832013-03-08 13:12:16 -0800600 iterate<DeferOperationHandler>(deferStruct.mRenderer, handler, level);
601}
602
603class ReplayOperationHandler {
604public:
Chris Craika08f95c2013-03-15 17:24:33 -0700605 ReplayOperationHandler(ReplayStateStruct& replayStruct, int level)
606 : mReplayStruct(replayStruct), mLevel(level) {}
Chet Haasedd671592013-04-19 14:54:34 -0700607 inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) {
Chris Craikff785832013-03-08 13:12:16 -0800608#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
Chris Craikd90144d2013-03-19 15:03:48 -0700609 mReplayStruct.mRenderer.eventMark(operation->name());
Chris Craikff785832013-03-08 13:12:16 -0800610#endif
Chet Haasedd671592013-04-19 14:54:34 -0700611 operation->replay(mReplayStruct, saveCount, mLevel, clipToBounds);
Chris Craikff785832013-03-08 13:12:16 -0800612 }
Chris Craikf57776b2013-10-25 18:30:17 -0700613 inline LinearAllocator& allocator() { return *(mReplayStruct.mAllocator); }
614
Chris Craikff785832013-03-08 13:12:16 -0800615private:
616 ReplayStateStruct& mReplayStruct;
Chris Craikff785832013-03-08 13:12:16 -0800617 const int mLevel;
618};
619
620void DisplayList::replay(ReplayStateStruct& replayStruct, const int level) {
Chris Craika08f95c2013-03-15 17:24:33 -0700621 ReplayOperationHandler handler(replayStruct, level);
Chris Craikff785832013-03-08 13:12:16 -0800622
623 replayStruct.mRenderer.startMark(mName.string());
624 iterate<ReplayOperationHandler>(replayStruct.mRenderer, handler, level);
625 replayStruct.mRenderer.endMark();
626
627 DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", level * 2, "", this, mName.string(),
628 replayStruct.mDrawGlStatus);
629}
630
Chris Craikf57776b2013-10-25 18:30:17 -0700631template <class T>
632void DisplayList::iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& renderer,
633 T& handler, const int level) {
634 if (m3dNodes.size() == 0 ||
Chris Craik9f68c092014-01-10 10:30:57 -0800635 (mode == kNegativeZChildren && m3dNodes[0].key > 0.0f) ||
636 (mode == kPositiveZChildren && m3dNodes[m3dNodes.size() - 1].key < 0.0f)) {
Chris Craikf533e942014-01-14 22:35:37 -0800637 // no 3d children to draw
Chris Craikf57776b2013-10-25 18:30:17 -0700638 return;
639 }
640
641 LinearAllocator& alloc = handler.allocator();
Chris Craikf533e942014-01-14 22:35:37 -0800642 ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, mWidth, mHeight,
Chris Craikf57776b2013-10-25 18:30:17 -0700643 SkRegion::kIntersect_Op); // clip to 3d root bounds for now
Chris Craikf533e942014-01-14 22:35:37 -0800644 handler(clipOp, PROPERTY_SAVECOUNT, mClipToBounds);
Chris Craikf57776b2013-10-25 18:30:17 -0700645 int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
646
Chris Craik564acf72014-01-02 16:46:18 -0800647 for (size_t i = 0; i < m3dNodes.size(); i++) {
Chris Craik9f68c092014-01-10 10:30:57 -0800648 const float zValue = m3dNodes[i].key;
Chris Craikf533e942014-01-14 22:35:37 -0800649 DrawDisplayListOp* childOp = m3dNodes[i].value;
Chris Craikf57776b2013-10-25 18:30:17 -0700650
651 if (mode == kPositiveZChildren && zValue < 0.0f) continue;
652 if (mode == kNegativeZChildren && zValue > 0.0f) break;
653
Chris Craik9f68c092014-01-10 10:30:57 -0800654 if (mode == kPositiveZChildren && zValue > 0.0f) {
655 /* draw shadow with parent matrix applied, passing in the child's total matrix
656 *
657 * TODO:
Chris Craik9f68c092014-01-10 10:30:57 -0800658 * -view must opt-in to shadows
Chris Craika2fe7af2014-01-28 17:25:06 -0800659 * -consider depth in more complex scenarios (neg z, added shadow depth)
Chris Craik9f68c092014-01-10 10:30:57 -0800660 */
Chris Craikf533e942014-01-14 22:35:37 -0800661 mat4 shadowMatrix(childOp->mTransformFromCompositingAncestor);
662 childOp->mDisplayList->applyViewPropertyTransforms(shadowMatrix);
Chris Craika2fe7af2014-01-28 17:25:06 -0800663 DisplayList* child = childOp->mDisplayList;
664
Chris Craik9f68c092014-01-10 10:30:57 -0800665 DisplayListOp* shadowOp = new (alloc) DrawShadowOp(shadowMatrix,
Chris Craika2fe7af2014-01-28 17:25:06 -0800666 child->mAlpha, &(child->mOutline), child->mWidth, child->mHeight);
Chris Craik9f68c092014-01-10 10:30:57 -0800667 handler(shadowOp, PROPERTY_SAVECOUNT, mClipToBounds);
Chris Craikf57776b2013-10-25 18:30:17 -0700668 }
Chris Craik9f68c092014-01-10 10:30:57 -0800669
Chris Craikf533e942014-01-14 22:35:37 -0800670 renderer.concatMatrix(childOp->mTransformFromCompositingAncestor);
671 childOp->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone
672 handler(childOp, renderer.getSaveCount() - 1, mClipToBounds);
673 childOp->mSkipInOrderDraw = true;
674 }
675 handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, mClipToBounds);
676}
677
678template <class T>
679void DisplayList::iterateProjectedChildren(OpenGLRenderer& renderer, T& handler, const int level) {
680 LinearAllocator& alloc = handler.allocator();
681 ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, mWidth, mHeight,
682 SkRegion::kReplace_Op); // clip to projection surface root bounds
683 handler(clipOp, PROPERTY_SAVECOUNT, mClipToBounds);
684 int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
685
686 for (size_t i = 0; i < mProjectedNodes.size(); i++) {
687 DrawDisplayListOp* childOp = mProjectedNodes[i];
688 renderer.concatMatrix(childOp->mTransformFromCompositingAncestor);
689 childOp->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone
690 handler(childOp, renderer.getSaveCount() - 1, mClipToBounds);
691 childOp->mSkipInOrderDraw = true;
Chris Craikf57776b2013-10-25 18:30:17 -0700692 }
693 handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, mClipToBounds);
694}
695
Chris Craikff785832013-03-08 13:12:16 -0800696/**
697 * This function serves both defer and replay modes, and will organize the displayList's component
698 * operations for a single frame:
699 *
Chris Craikf57776b2013-10-25 18:30:17 -0700700 * Every 'simple' state operation that affects just the matrix and alpha (or other factors of
Chris Craikff785832013-03-08 13:12:16 -0800701 * DeferredDisplayState) may be issued directly to the renderer, but complex operations (with custom
702 * defer logic) and operations in displayListOps are issued through the 'handler' which handles the
703 * defer vs replay logic, per operation
704 */
705template <class T>
706void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level) {
Chris Craik9846de62013-06-12 16:23:00 -0700707 if (CC_UNLIKELY(mDestroyed)) { // temporary debug logging
708 ALOGW("Error: %s is drawing after destruction, size %d", getName(), mSize);
709 CRASH();
710 }
711 if (mSize == 0 || mAlpha <= 0) {
Chris Craikff785832013-03-08 13:12:16 -0800712 DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, mName.string());
713 return;
714 }
Chris Craik0776a602013-02-14 15:36:01 -0800715
716#if DEBUG_DISPLAY_LIST
717 Rect* clipRect = renderer.getClipRect();
Chris Craik527a3aa2013-03-04 10:19:31 -0800718 DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.0f, %.0f, %.0f",
Chris Craikff785832013-03-08 13:12:16 -0800719 level * 2, "", this, mName.string(), clipRect->left, clipRect->top,
Chris Craik0776a602013-02-14 15:36:01 -0800720 clipRect->right, clipRect->bottom);
721#endif
722
Chris Craikf57776b2013-10-25 18:30:17 -0700723 LinearAllocator& alloc = handler.allocator();
Chris Craikff785832013-03-08 13:12:16 -0800724 int restoreTo = renderer.getSaveCount();
Chris Craikf57776b2013-10-25 18:30:17 -0700725 handler(new (alloc) SaveOp(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag),
Chet Haasedd671592013-04-19 14:54:34 -0700726 PROPERTY_SAVECOUNT, mClipToBounds);
Chris Craik0776a602013-02-14 15:36:01 -0800727
Chris Craikff785832013-03-08 13:12:16 -0800728 DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "",
Chris Craik0776a602013-02-14 15:36:01 -0800729 SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
Chris Craikc3566d02013-02-04 16:16:33 -0800730
Chris Craikff785832013-03-08 13:12:16 -0800731 setViewProperties<T>(renderer, handler, level + 1);
Chris Craik0776a602013-02-14 15:36:01 -0800732
Chris Craikf57776b2013-10-25 18:30:17 -0700733 bool quickRejected = mClipToBounds && renderer.quickRejectConservative(0, 0, mWidth, mHeight);
734 if (!quickRejected) {
Chris Craik9f68c092014-01-10 10:30:57 -0800735 // Z sort 3d children (stable-ness makes z compare fall back to standard drawing order)
736 std::stable_sort(m3dNodes.begin(), m3dNodes.end());
737
Chris Craikf57776b2013-10-25 18:30:17 -0700738 // for 3d root, draw children with negative z values
739 iterate3dChildren(kNegativeZChildren, renderer, handler, level);
Chris Craik0776a602013-02-14 15:36:01 -0800740
Chris Craikf57776b2013-10-25 18:30:17 -0700741 DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
742 const int saveCountOffset = renderer.getSaveCount() - 1;
Chris Craikf533e942014-01-14 22:35:37 -0800743 const int projectionIndex = mDisplayListData->projectionIndex;
Chris Craikf57776b2013-10-25 18:30:17 -0700744 for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
745 DisplayListOp *op = mDisplayListData->displayListOps[i];
Chris Craikff785832013-03-08 13:12:16 -0800746
Chris Craik6045d2b2013-05-21 10:49:47 -0700747#if DEBUG_DISPLAY_LIST
Chris Craikf57776b2013-10-25 18:30:17 -0700748 op->output(level + 1);
Chris Craik6045d2b2013-05-21 10:49:47 -0700749#endif
750
Chris Craikf57776b2013-10-25 18:30:17 -0700751 logBuffer.writeCommand(level, op->name());
752 handler(op, saveCountOffset, mClipToBounds);
Chris Craikf533e942014-01-14 22:35:37 -0800753
754 if (CC_UNLIKELY(i == projectionIndex && mProjectedNodes.size() > 0)) {
755 iterateProjectedChildren(renderer, handler, level);
756 }
Chris Craikf57776b2013-10-25 18:30:17 -0700757 }
758
759 // for 3d root, draw children with positive z values
760 iterate3dChildren(kPositiveZChildren, renderer, handler, level);
Chris Craik0776a602013-02-14 15:36:01 -0800761 }
762
Chris Craikff785832013-03-08 13:12:16 -0800763 DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
Chris Craikf57776b2013-10-25 18:30:17 -0700764 handler(new (alloc) RestoreToCountOp(restoreTo),
765 PROPERTY_SAVECOUNT, mClipToBounds);
Chris Craik16ecda52013-03-29 10:59:59 -0700766 renderer.setOverrideLayerAlpha(1.0f);
Chris Craik0776a602013-02-14 15:36:01 -0800767}
768
769}; // namespace uirenderer
770}; // namespace android