blob: c616cd8c349f0d4afef3a524a981dfe06fbc8308 [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>
20
Chris Craikf57776b2013-10-25 18:30:17 -070021#include <utils/Trace.h>
22
Chris Craikc3566d02013-02-04 16:16:33 -080023#include "Debug.h"
Chris Craik0776a602013-02-14 15:36:01 -080024#include "DisplayList.h"
25#include "DisplayListOp.h"
26#include "DisplayListLogBuffer.h"
27
28namespace android {
29namespace uirenderer {
30
31void DisplayList::outputLogBuffer(int fd) {
32 DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
33 if (logBuffer.isEmpty()) {
34 return;
35 }
36
37 FILE *file = fdopen(fd, "a");
38
39 fprintf(file, "\nRecent DisplayList operations\n");
40 logBuffer.outputCommands(file);
41
42 String8 cachesLog;
43 Caches::getInstance().dumpMemoryUsage(cachesLog);
44 fprintf(file, "\nCaches:\n%s", cachesLog.string());
45 fprintf(file, "\n");
46
47 fflush(file);
48}
49
50DisplayList::DisplayList(const DisplayListRenderer& recorder) :
Chris Craik9846de62013-06-12 16:23:00 -070051 mDestroyed(false), mTransformMatrix(NULL), mTransformCamera(NULL), mTransformMatrix3D(NULL),
Chris Craik0776a602013-02-14 15:36:01 -080052 mStaticMatrix(NULL), mAnimationMatrix(NULL) {
53
54 initFromDisplayListRenderer(recorder);
55}
56
57DisplayList::~DisplayList() {
Chris Craik9846de62013-06-12 16:23:00 -070058 mDestroyed = true;
Chris Craik0776a602013-02-14 15:36:01 -080059 clearResources();
60}
61
62void DisplayList::destroyDisplayListDeferred(DisplayList* displayList) {
63 if (displayList) {
64 DISPLAY_LIST_LOGD("Deferring display list destruction");
65 Caches::getInstance().deleteDisplayListDeferred(displayList);
66 }
67}
68
69void DisplayList::clearResources() {
70 mDisplayListData = NULL;
Chris Craikff785832013-03-08 13:12:16 -080071
Chris Craik0776a602013-02-14 15:36:01 -080072 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
Romain Guye3b0a012013-06-26 15:45:41 -0700102 for (size_t i = 0; i < mPatchResources.size(); i++) {
103 caches.resourceCache.decrementRefcountLocked(mPatchResources.itemAt(i));
104 }
105
Chris Craik0776a602013-02-14 15:36:01 -0800106 for (size_t i = 0; i < mShaders.size(); i++) {
107 caches.resourceCache.decrementRefcountLocked(mShaders.itemAt(i));
108 caches.resourceCache.destructorLocked(mShaders.itemAt(i));
109 }
110
111 for (size_t i = 0; i < mSourcePaths.size(); i++) {
112 caches.resourceCache.decrementRefcountLocked(mSourcePaths.itemAt(i));
113 }
114
115 for (size_t i = 0; i < mLayers.size(); i++) {
116 caches.resourceCache.decrementRefcountLocked(mLayers.itemAt(i));
117 }
118
119 caches.resourceCache.unlock();
120
121 for (size_t i = 0; i < mPaints.size(); i++) {
122 delete mPaints.itemAt(i);
123 }
124
125 for (size_t i = 0; i < mRegions.size(); i++) {
126 delete mRegions.itemAt(i);
127 }
128
129 for (size_t i = 0; i < mPaths.size(); i++) {
Romain Guyc46d07a2013-03-15 19:06:39 -0700130 delete mPaths.itemAt(i);
Chris Craik0776a602013-02-14 15:36:01 -0800131 }
132
133 for (size_t i = 0; i < mMatrices.size(); i++) {
134 delete mMatrices.itemAt(i);
135 }
136
137 mBitmapResources.clear();
138 mOwnedBitmapResources.clear();
139 mFilterResources.clear();
Romain Guye3b0a012013-06-26 15:45:41 -0700140 mPatchResources.clear();
Chris Craik0776a602013-02-14 15:36:01 -0800141 mShaders.clear();
142 mSourcePaths.clear();
143 mPaints.clear();
144 mRegions.clear();
145 mPaths.clear();
146 mMatrices.clear();
147 mLayers.clear();
148}
149
150void DisplayList::reset() {
151 clearResources();
152 init();
153}
154
155void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing) {
156 if (reusing) {
157 // re-using display list - clear out previous allocations
158 clearResources();
159 }
160
161 init();
162
163 mDisplayListData = recorder.getDisplayListData();
164 mSize = mDisplayListData->allocator.usedSize();
165
166 if (mSize == 0) {
167 return;
168 }
169
170 mFunctorCount = recorder.getFunctorCount();
171
172 Caches& caches = Caches::getInstance();
173 caches.registerFunctors(mFunctorCount);
174 caches.resourceCache.lock();
175
176 const Vector<SkBitmap*>& bitmapResources = recorder.getBitmapResources();
177 for (size_t i = 0; i < bitmapResources.size(); i++) {
178 SkBitmap* resource = bitmapResources.itemAt(i);
179 mBitmapResources.add(resource);
180 caches.resourceCache.incrementRefcountLocked(resource);
181 }
182
183 const Vector<SkBitmap*> &ownedBitmapResources = recorder.getOwnedBitmapResources();
184 for (size_t i = 0; i < ownedBitmapResources.size(); i++) {
185 SkBitmap* resource = ownedBitmapResources.itemAt(i);
186 mOwnedBitmapResources.add(resource);
187 caches.resourceCache.incrementRefcountLocked(resource);
188 }
189
190 const Vector<SkiaColorFilter*>& filterResources = recorder.getFilterResources();
191 for (size_t i = 0; i < filterResources.size(); i++) {
192 SkiaColorFilter* resource = filterResources.itemAt(i);
193 mFilterResources.add(resource);
194 caches.resourceCache.incrementRefcountLocked(resource);
195 }
196
Romain Guye3b0a012013-06-26 15:45:41 -0700197 const Vector<Res_png_9patch*>& patchResources = recorder.getPatchResources();
198 for (size_t i = 0; i < patchResources.size(); i++) {
199 Res_png_9patch* resource = patchResources.itemAt(i);
200 mPatchResources.add(resource);
201 caches.resourceCache.incrementRefcountLocked(resource);
202 }
203
Chris Craik0776a602013-02-14 15:36:01 -0800204 const Vector<SkiaShader*>& shaders = recorder.getShaders();
205 for (size_t i = 0; i < shaders.size(); i++) {
206 SkiaShader* resource = shaders.itemAt(i);
207 mShaders.add(resource);
208 caches.resourceCache.incrementRefcountLocked(resource);
209 }
210
211 const SortedVector<SkPath*>& sourcePaths = recorder.getSourcePaths();
212 for (size_t i = 0; i < sourcePaths.size(); i++) {
213 mSourcePaths.add(sourcePaths.itemAt(i));
214 caches.resourceCache.incrementRefcountLocked(sourcePaths.itemAt(i));
215 }
216
217 const Vector<Layer*>& layers = recorder.getLayers();
218 for (size_t i = 0; i < layers.size(); i++) {
219 mLayers.add(layers.itemAt(i));
220 caches.resourceCache.incrementRefcountLocked(layers.itemAt(i));
221 }
222
223 caches.resourceCache.unlock();
224
225 mPaints.appendVector(recorder.getPaints());
226 mRegions.appendVector(recorder.getRegions());
227 mPaths.appendVector(recorder.getPaths());
228 mMatrices.appendVector(recorder.getMatrices());
229}
230
231void DisplayList::init() {
232 mSize = 0;
233 mIsRenderable = true;
234 mFunctorCount = 0;
235 mLeft = 0;
236 mTop = 0;
237 mRight = 0;
238 mBottom = 0;
Chet Haasedd671592013-04-19 14:54:34 -0700239 mClipToBounds = true;
Chris Craik0776a602013-02-14 15:36:01 -0800240 mAlpha = 1;
Chris Craik0776a602013-02-14 15:36:01 -0800241 mHasOverlappingRendering = true;
242 mTranslationX = 0;
243 mTranslationY = 0;
Chris Craikf57776b2013-10-25 18:30:17 -0700244 mTranslationZ = 0;
Chris Craik0776a602013-02-14 15:36:01 -0800245 mRotation = 0;
246 mRotationX = 0;
247 mRotationY= 0;
248 mScaleX = 1;
249 mScaleY = 1;
250 mPivotX = 0;
251 mPivotY = 0;
252 mCameraDistance = 0;
253 mMatrixDirty = false;
254 mMatrixFlags = 0;
255 mPrevWidth = -1;
256 mPrevHeight = -1;
257 mWidth = 0;
258 mHeight = 0;
259 mPivotExplicitlySet = false;
260 mCaching = false;
Chris Craikf57776b2013-10-25 18:30:17 -0700261 mIs3dRoot = true; // TODO: setter, java side impl
Chris Craik0776a602013-02-14 15:36:01 -0800262}
263
264size_t DisplayList::getSize() {
265 return mSize;
266}
267
268/**
269 * This function is a simplified version of replay(), where we simply retrieve and log the
270 * display list. This function should remain in sync with the replay() function.
271 */
272void DisplayList::output(uint32_t level) {
Romain Guy7031ff62013-02-22 11:48:16 -0800273 ALOGD("%*sStart display list (%p, %s, render=%d)", (level - 1) * 2, "", this,
Chris Craik0776a602013-02-14 15:36:01 -0800274 mName.string(), isRenderable());
Romain Guy7031ff62013-02-22 11:48:16 -0800275 ALOGD("%*s%s %d", level * 2, "", "Save",
276 SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
Chris Craik0776a602013-02-14 15:36:01 -0800277
Chris Craik0776a602013-02-14 15:36:01 -0800278 outputViewProperties(level);
279 int flags = DisplayListOp::kOpLogFlag_Recurse;
280 for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
281 mDisplayListData->displayListOps[i]->output(level, flags);
282 }
Romain Guy7031ff62013-02-22 11:48:16 -0800283
284 ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, mName.string());
Chris Craik0776a602013-02-14 15:36:01 -0800285}
286
Romain Guy52036b12013-02-14 18:03:37 -0800287float DisplayList::getPivotX() {
288 updateMatrix();
289 return mPivotX;
290}
291
292float DisplayList::getPivotY() {
293 updateMatrix();
294 return mPivotY;
295}
296
Chris Craik0776a602013-02-14 15:36:01 -0800297void DisplayList::updateMatrix() {
298 if (mMatrixDirty) {
299 if (!mTransformMatrix) {
300 mTransformMatrix = new SkMatrix();
301 }
302 if (mMatrixFlags == 0 || mMatrixFlags == TRANSLATION) {
303 mTransformMatrix->reset();
304 } else {
305 if (!mPivotExplicitlySet) {
306 if (mWidth != mPrevWidth || mHeight != mPrevHeight) {
307 mPrevWidth = mWidth;
308 mPrevHeight = mHeight;
Chet Haase259b6962013-05-03 15:25:33 -0700309 mPivotX = mPrevWidth / 2.0f;
310 mPivotY = mPrevHeight / 2.0f;
Chris Craik0776a602013-02-14 15:36:01 -0800311 }
312 }
Chris Craikf57776b2013-10-25 18:30:17 -0700313 if (!DEBUG_ENABLE_3D && (mMatrixFlags & ROTATION_3D) == 0) {
Chris Craik0776a602013-02-14 15:36:01 -0800314 mTransformMatrix->setTranslate(mTranslationX, mTranslationY);
315 mTransformMatrix->preRotate(mRotation, mPivotX, mPivotY);
316 mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY);
317 } else {
Chris Craikf57776b2013-10-25 18:30:17 -0700318 if (DEBUG_ENABLE_3D) {
319 mTransform.loadTranslate(mPivotX + mTranslationX, mPivotY + mTranslationY,
320 mTranslationZ);
321 mTransform.rotate(mRotationX, 1, 0, 0);
322 mTransform.rotate(mRotationY, 0, 1, 0);
323 mTransform.rotate(mRotation, 0, 0, 1);
324 mTransform.scale(mScaleX, mScaleY, 1);
325 mTransform.translate(-mPivotX, -mPivotY);
326 } else {
327 /* TODO: support this old transform approach, based on API level */
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();
Chris Craik0776a602013-02-14 15:36:01 -0800344 }
Chris Craik0776a602013-02-14 15:36:01 -0800345 }
346 }
347 mMatrixDirty = false;
348 }
349}
350
Chris Craikff785832013-03-08 13:12:16 -0800351void DisplayList::outputViewProperties(const int level) {
Chris Craik0776a602013-02-14 15:36:01 -0800352 updateMatrix();
353 if (mLeft != 0 || mTop != 0) {
354 ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", mLeft, mTop);
355 }
356 if (mStaticMatrix) {
357 ALOGD("%*sConcatMatrix (static) %p: " MATRIX_STRING,
358 level * 2, "", mStaticMatrix, MATRIX_ARGS(mStaticMatrix));
359 }
360 if (mAnimationMatrix) {
361 ALOGD("%*sConcatMatrix (animation) %p: " MATRIX_STRING,
Chris Craik66063ae2013-09-05 16:11:18 -0700362 level * 2, "", mAnimationMatrix, MATRIX_ARGS(mAnimationMatrix));
Chris Craik0776a602013-02-14 15:36:01 -0800363 }
364 if (mMatrixFlags != 0) {
365 if (mMatrixFlags == TRANSLATION) {
366 ALOGD("%*sTranslate %f, %f", level * 2, "", mTranslationX, mTranslationY);
367 } else {
368 ALOGD("%*sConcatMatrix %p: " MATRIX_STRING,
369 level * 2, "", mTransformMatrix, MATRIX_ARGS(mTransformMatrix));
370 }
371 }
Chris Craik39a908c2013-06-13 14:39:01 -0700372
Romain Guy1de466f2013-09-12 16:09:19 -0700373 bool clipToBoundsNeeded = mCaching ? false : mClipToBounds;
Chris Craik5f803622013-03-21 14:39:04 -0700374 if (mAlpha < 1) {
Chris Craik16ecda52013-03-29 10:59:59 -0700375 if (mCaching) {
376 ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mAlpha);
377 } else if (!mHasOverlappingRendering) {
Chris Craik5f803622013-03-21 14:39:04 -0700378 ALOGD("%*sScaleAlpha %.2f", level * 2, "", mAlpha);
Chris Craik0776a602013-02-14 15:36:01 -0800379 } else {
380 int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
Chris Craik39a908c2013-06-13 14:39:01 -0700381 if (clipToBoundsNeeded) {
Chris Craik0776a602013-02-14 15:36:01 -0800382 flags |= SkCanvas::kClipToLayer_SaveFlag;
Chris Craik39a908c2013-06-13 14:39:01 -0700383 clipToBoundsNeeded = false; // clipping done by save layer
Chris Craik0776a602013-02-14 15:36:01 -0800384 }
385 ALOGD("%*sSaveLayerAlpha %.2f, %.2f, %.2f, %.2f, %d, 0x%x", level * 2, "",
386 (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop,
Chris Craika08f95c2013-03-15 17:24:33 -0700387 (int)(mAlpha * 255), flags);
Chris Craik0776a602013-02-14 15:36:01 -0800388 }
389 }
Chris Craik39a908c2013-06-13 14:39:01 -0700390 if (clipToBoundsNeeded) {
Chris Craik0776a602013-02-14 15:36:01 -0800391 ALOGD("%*sClipRect %.2f, %.2f, %.2f, %.2f", level * 2, "", 0.0f, 0.0f,
392 (float) mRight - mLeft, (float) mBottom - mTop);
393 }
394}
395
Chris Craikff785832013-03-08 13:12:16 -0800396/*
397 * For property operations, we pass a savecount of 0, since the operations aren't part of the
398 * displaylist, and thus don't have to compensate for the record-time/playback-time discrepancy in
399 * base saveCount (i.e., how RestoreToCount uses saveCount + mCount)
400 */
401#define PROPERTY_SAVECOUNT 0
402
403template <class T>
404void DisplayList::setViewProperties(OpenGLRenderer& renderer, T& handler,
405 const int level) {
406#if DEBUG_DISPLAY_LIST
Chris Craik0776a602013-02-14 15:36:01 -0800407 outputViewProperties(level);
408#endif
409 updateMatrix();
410 if (mLeft != 0 || mTop != 0) {
411 renderer.translate(mLeft, mTop);
412 }
413 if (mStaticMatrix) {
414 renderer.concatMatrix(mStaticMatrix);
415 } else if (mAnimationMatrix) {
416 renderer.concatMatrix(mAnimationMatrix);
417 }
418 if (mMatrixFlags != 0) {
419 if (mMatrixFlags == TRANSLATION) {
420 renderer.translate(mTranslationX, mTranslationY);
Chris Craikf57776b2013-10-25 18:30:17 -0700421 renderer.translateZ(mTranslationZ);
Chris Craik0776a602013-02-14 15:36:01 -0800422 } else {
Chris Craikf57776b2013-10-25 18:30:17 -0700423#if DEBUG_ENABLE_3D
424 renderer.concatMatrix(mTransform);
425#else
Chris Craik0776a602013-02-14 15:36:01 -0800426 renderer.concatMatrix(mTransformMatrix);
Chris Craikf57776b2013-10-25 18:30:17 -0700427#endif
Chris Craik0776a602013-02-14 15:36:01 -0800428 }
429 }
Romain Guy1de466f2013-09-12 16:09:19 -0700430 bool clipToBoundsNeeded = mCaching ? false : mClipToBounds;
Chris Craika08f95c2013-03-15 17:24:33 -0700431 if (mAlpha < 1) {
Chris Craik16ecda52013-03-29 10:59:59 -0700432 if (mCaching) {
433 renderer.setOverrideLayerAlpha(mAlpha);
434 } else if (!mHasOverlappingRendering) {
Chris Craika08f95c2013-03-15 17:24:33 -0700435 renderer.scaleAlpha(mAlpha);
Chris Craik0776a602013-02-14 15:36:01 -0800436 } else {
437 // TODO: should be able to store the size of a DL at record time and not
438 // have to pass it into this call. In fact, this information might be in the
439 // location/size info that we store with the new native transform data.
Chris Craikff785832013-03-08 13:12:16 -0800440 int saveFlags = SkCanvas::kHasAlphaLayer_SaveFlag;
Chris Craik39a908c2013-06-13 14:39:01 -0700441 if (clipToBoundsNeeded) {
Chris Craikff785832013-03-08 13:12:16 -0800442 saveFlags |= SkCanvas::kClipToLayer_SaveFlag;
Chris Craik39a908c2013-06-13 14:39:01 -0700443 clipToBoundsNeeded = false; // clipping done by saveLayer
Chris Craik0776a602013-02-14 15:36:01 -0800444 }
Chris Craikf57776b2013-10-25 18:30:17 -0700445
446 SaveLayerOp* op = new (handler.allocator()) SaveLayerOp(
447 0, 0, mRight - mLeft, mBottom - mTop,
448 mAlpha * 255, SkXfermode::kSrcOver_Mode, saveFlags);
449 handler(op, PROPERTY_SAVECOUNT, mClipToBounds);
Chris Craik0776a602013-02-14 15:36:01 -0800450 }
451 }
Chris Craik39a908c2013-06-13 14:39:01 -0700452 if (clipToBoundsNeeded) {
Chris Craikf57776b2013-10-25 18:30:17 -0700453 ClipRectOp* op = new (handler.allocator()) ClipRectOp(0, 0,
454 mRight - mLeft, mBottom - mTop, SkRegion::kIntersect_Op);
455 handler(op, PROPERTY_SAVECOUNT, mClipToBounds);
456 }
457}
458
459/**
460 * Apply property-based transformations to input matrix
461 */
462void DisplayList::applyViewPropertyTransforms(mat4& matrix) {
463 if (mLeft != 0 || mTop != 0) {
464 matrix.translate(mLeft, mTop);
465 }
466 if (mStaticMatrix) {
467 mat4 stat(*mStaticMatrix);
468 matrix.multiply(stat);
469 } else if (mAnimationMatrix) {
470 mat4 anim(*mAnimationMatrix);
471 matrix.multiply(anim);
472 }
473 if (mMatrixFlags != 0) {
474 if (mMatrixFlags == TRANSLATION) {
475 matrix.translate(mTranslationX, mTranslationY, mTranslationZ);
476 } else {
477#if DEBUG_ENABLE_3D
478 matrix.multiply(mTransform);
479#else
480 mat4 temp(*mTransformMatrix);
481 matrix.multiply(temp);
482#endif
483 }
484 }
485}
486
487/**
488 * Organizes the DisplayList hierarchy to prepare for Z-based draw order.
489 *
490 * This should be called before a call to defer() or drawDisplayList()
491 *
492 * Each DisplayList that serves as a 3d root builds its list of composited children,
493 * which are flagged to not draw in the standard draw loop.
494 */
495void DisplayList::computeOrdering() {
496 ATRACE_CALL();
497 mat4::identity();
498 for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) {
499 DrawDisplayListOp* childOp = mDisplayListData->children[i];
500 childOp->mDisplayList->computeOrderingImpl(childOp, &m3dNodes, &mat4::identity());
501 }
502}
503
504void DisplayList::computeOrderingImpl(
505 DrawDisplayListOp* opState,
506 KeyedVector<float, Vector<DrawDisplayListOp*> >* compositedChildrenOf3dRoot,
507 const mat4* transformFrom3dRoot) {
508 // TODO: should avoid this calculation in most cases
509 opState->mTransformFrom3dRoot.load(*transformFrom3dRoot);
510 opState->mTransformFrom3dRoot.multiply(opState->mTransformFromParent);
511
512 if (mTranslationZ != 0.0f) { // TODO: other signals, such as custom 4x4 matrix
513 // composited layer, insert into current 3d root and flag for out of order draw
514 opState->mSkipInOrderDraw = true;
515
516 Vector3 pivot(mPivotX, mPivotY, 0.0f);
517 mat4 totalTransform(opState->mTransformFrom3dRoot);
518 applyViewPropertyTransforms(totalTransform);
519 totalTransform.mapPoint3d(pivot);
520 const float key = pivot.z;
521
522 if (compositedChildrenOf3dRoot->indexOfKey(key) < 0) {
523 compositedChildrenOf3dRoot->add(key, Vector<DrawDisplayListOp*>());
524 }
525 compositedChildrenOf3dRoot->editValueFor(key).push(opState);
526 } else {
527 // standard in order draw
528 opState->mSkipInOrderDraw = false;
529 }
530
531 m3dNodes.clear();
532 if (mIs3dRoot) {
533 // create a new 3d space for children by separating their ordering
534 compositedChildrenOf3dRoot = &m3dNodes;
535 transformFrom3dRoot = &mat4::identity();
536 } else {
537 transformFrom3dRoot = &(opState->mTransformFrom3dRoot);
538 }
539
540 if (mDisplayListData->children.size() > 0) {
541 for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) {
542 DrawDisplayListOp* childOp = mDisplayListData->children[i];
543 childOp->mDisplayList->computeOrderingImpl(childOp,
544 compositedChildrenOf3dRoot, transformFrom3dRoot);
545 }
Chris Craik0776a602013-02-14 15:36:01 -0800546 }
547}
548
Chris Craikff785832013-03-08 13:12:16 -0800549class DeferOperationHandler {
550public:
Chris Craika08f95c2013-03-15 17:24:33 -0700551 DeferOperationHandler(DeferStateStruct& deferStruct, int level)
552 : mDeferStruct(deferStruct), mLevel(level) {}
Chet Haasedd671592013-04-19 14:54:34 -0700553 inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) {
554 operation->defer(mDeferStruct, saveCount, mLevel, clipToBounds);
Chris Craikff785832013-03-08 13:12:16 -0800555 }
Chris Craikf57776b2013-10-25 18:30:17 -0700556 inline LinearAllocator& allocator() { return *(mDeferStruct.mAllocator); }
557
Chris Craikff785832013-03-08 13:12:16 -0800558private:
559 DeferStateStruct& mDeferStruct;
Chris Craikff785832013-03-08 13:12:16 -0800560 const int mLevel;
561};
562
563void DisplayList::defer(DeferStateStruct& deferStruct, const int level) {
Chris Craika08f95c2013-03-15 17:24:33 -0700564 DeferOperationHandler handler(deferStruct, level);
Chris Craikff785832013-03-08 13:12:16 -0800565 iterate<DeferOperationHandler>(deferStruct.mRenderer, handler, level);
566}
567
568class ReplayOperationHandler {
569public:
Chris Craika08f95c2013-03-15 17:24:33 -0700570 ReplayOperationHandler(ReplayStateStruct& replayStruct, int level)
571 : mReplayStruct(replayStruct), mLevel(level) {}
Chet Haasedd671592013-04-19 14:54:34 -0700572 inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) {
Chris Craikff785832013-03-08 13:12:16 -0800573#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
Chris Craikd90144d2013-03-19 15:03:48 -0700574 mReplayStruct.mRenderer.eventMark(operation->name());
Chris Craikff785832013-03-08 13:12:16 -0800575#endif
Chet Haasedd671592013-04-19 14:54:34 -0700576 operation->replay(mReplayStruct, saveCount, mLevel, clipToBounds);
Chris Craikff785832013-03-08 13:12:16 -0800577 }
Chris Craikf57776b2013-10-25 18:30:17 -0700578 inline LinearAllocator& allocator() { return *(mReplayStruct.mAllocator); }
579
Chris Craikff785832013-03-08 13:12:16 -0800580private:
581 ReplayStateStruct& mReplayStruct;
Chris Craikff785832013-03-08 13:12:16 -0800582 const int mLevel;
583};
584
585void DisplayList::replay(ReplayStateStruct& replayStruct, const int level) {
Chris Craika08f95c2013-03-15 17:24:33 -0700586 ReplayOperationHandler handler(replayStruct, level);
Chris Craikff785832013-03-08 13:12:16 -0800587
588 replayStruct.mRenderer.startMark(mName.string());
589 iterate<ReplayOperationHandler>(replayStruct.mRenderer, handler, level);
590 replayStruct.mRenderer.endMark();
591
592 DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", level * 2, "", this, mName.string(),
593 replayStruct.mDrawGlStatus);
594}
595
Chris Craikf57776b2013-10-25 18:30:17 -0700596template <class T>
597void DisplayList::iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& renderer,
598 T& handler, const int level) {
599 if (m3dNodes.size() == 0 ||
600 (mode == kNegativeZChildren && m3dNodes.keyAt(0) > 0.0f) ||
601 (mode == kPositiveZChildren && m3dNodes.keyAt(m3dNodes.size() - 1) < 0.0f)) {
602 // nothing to draw
603 return;
604 }
605
606 LinearAllocator& alloc = handler.allocator();
607 ClipRectOp* op = new (alloc) ClipRectOp(0, 0, mWidth, mHeight,
608 SkRegion::kIntersect_Op); // clip to 3d root bounds for now
609 handler(op, PROPERTY_SAVECOUNT, mClipToBounds);
610 int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
611
612 for (int i = 0; i < m3dNodes.size(); i++) {
613 const float zValue = m3dNodes.keyAt(i);
614
615 if (mode == kPositiveZChildren && zValue < 0.0f) continue;
616 if (mode == kNegativeZChildren && zValue > 0.0f) break;
617
618 const Vector<DrawDisplayListOp*>& nodesAtZ = m3dNodes[i];
619 for (int j = 0; j < nodesAtZ.size(); j++) {
620 DrawDisplayListOp* op = nodesAtZ[j];
621 if (mode == kPositiveZChildren) {
622 /* draw shadow on renderer with parent matrix applied, passing in the child's total matrix
623 *
624 * TODO:
625 * -determine and pass background shape (and possibly drawable alpha)
626 * -view must opt-in to shadows
627 * -consider shadows for other content
628 */
629 mat4 shadowMatrix(op->mTransformFrom3dRoot);
630 op->mDisplayList->applyViewPropertyTransforms(shadowMatrix);
631 DisplayListOp* shadowOp = new (alloc) DrawShadowOp(shadowMatrix, op->mDisplayList->mAlpha,
632 op->mDisplayList->getWidth(), op->mDisplayList->getHeight());
633 handler(shadowOp, PROPERTY_SAVECOUNT, mClipToBounds);
634 }
635
636 renderer.concatMatrix(op->mTransformFrom3dRoot);
637 op->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone
638 handler(op, renderer.getSaveCount() - 1, mClipToBounds);
639 op->mSkipInOrderDraw = true;
640 }
641 }
642 handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, mClipToBounds);
643}
644
Chris Craikff785832013-03-08 13:12:16 -0800645/**
646 * This function serves both defer and replay modes, and will organize the displayList's component
647 * operations for a single frame:
648 *
Chris Craikf57776b2013-10-25 18:30:17 -0700649 * Every 'simple' state operation that affects just the matrix and alpha (or other factors of
Chris Craikff785832013-03-08 13:12:16 -0800650 * DeferredDisplayState) may be issued directly to the renderer, but complex operations (with custom
651 * defer logic) and operations in displayListOps are issued through the 'handler' which handles the
652 * defer vs replay logic, per operation
653 */
654template <class T>
655void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level) {
Chris Craik9846de62013-06-12 16:23:00 -0700656 if (CC_UNLIKELY(mDestroyed)) { // temporary debug logging
657 ALOGW("Error: %s is drawing after destruction, size %d", getName(), mSize);
658 CRASH();
659 }
660 if (mSize == 0 || mAlpha <= 0) {
Chris Craikff785832013-03-08 13:12:16 -0800661 DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, mName.string());
662 return;
663 }
Chris Craik0776a602013-02-14 15:36:01 -0800664
665#if DEBUG_DISPLAY_LIST
666 Rect* clipRect = renderer.getClipRect();
Chris Craik527a3aa2013-03-04 10:19:31 -0800667 DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.0f, %.0f, %.0f",
Chris Craikff785832013-03-08 13:12:16 -0800668 level * 2, "", this, mName.string(), clipRect->left, clipRect->top,
Chris Craik0776a602013-02-14 15:36:01 -0800669 clipRect->right, clipRect->bottom);
670#endif
671
Chris Craikf57776b2013-10-25 18:30:17 -0700672 LinearAllocator& alloc = handler.allocator();
Chris Craikff785832013-03-08 13:12:16 -0800673 int restoreTo = renderer.getSaveCount();
Chris Craikf57776b2013-10-25 18:30:17 -0700674 handler(new (alloc) SaveOp(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag),
Chet Haasedd671592013-04-19 14:54:34 -0700675 PROPERTY_SAVECOUNT, mClipToBounds);
Chris Craik0776a602013-02-14 15:36:01 -0800676
Chris Craikff785832013-03-08 13:12:16 -0800677 DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "",
Chris Craik0776a602013-02-14 15:36:01 -0800678 SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
Chris Craikc3566d02013-02-04 16:16:33 -0800679
Chris Craikff785832013-03-08 13:12:16 -0800680 setViewProperties<T>(renderer, handler, level + 1);
Chris Craik0776a602013-02-14 15:36:01 -0800681
Chris Craikf57776b2013-10-25 18:30:17 -0700682 bool quickRejected = mClipToBounds && renderer.quickRejectConservative(0, 0, mWidth, mHeight);
683 if (!quickRejected) {
684 // for 3d root, draw children with negative z values
685 iterate3dChildren(kNegativeZChildren, renderer, handler, level);
Chris Craik0776a602013-02-14 15:36:01 -0800686
Chris Craikf57776b2013-10-25 18:30:17 -0700687 DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
688 const int saveCountOffset = renderer.getSaveCount() - 1;
689 for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
690 DisplayListOp *op = mDisplayListData->displayListOps[i];
Chris Craikff785832013-03-08 13:12:16 -0800691
Chris Craik6045d2b2013-05-21 10:49:47 -0700692#if DEBUG_DISPLAY_LIST
Chris Craikf57776b2013-10-25 18:30:17 -0700693 op->output(level + 1);
Chris Craik6045d2b2013-05-21 10:49:47 -0700694#endif
695
Chris Craikf57776b2013-10-25 18:30:17 -0700696 logBuffer.writeCommand(level, op->name());
697 handler(op, saveCountOffset, mClipToBounds);
698 }
699
700 // for 3d root, draw children with positive z values
701 iterate3dChildren(kPositiveZChildren, renderer, handler, level);
Chris Craik0776a602013-02-14 15:36:01 -0800702 }
703
Chris Craikff785832013-03-08 13:12:16 -0800704 DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
Chris Craikf57776b2013-10-25 18:30:17 -0700705 handler(new (alloc) RestoreToCountOp(restoreTo),
706 PROPERTY_SAVECOUNT, mClipToBounds);
Chris Craik16ecda52013-03-29 10:59:59 -0700707 renderer.setOverrideLayerAlpha(1.0f);
Chris Craik0776a602013-02-14 15:36:01 -0800708}
709
710}; // namespace uirenderer
711}; // namespace android