DisplayList.cpp revision 58f09b352417c4ff7e01365727cbf8a09b9bed23
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#define ATRACE_TAG ATRACE_TAG_VIEW 18 19#include <SkCanvas.h> 20 21#include <utils/Trace.h> 22 23#include "Debug.h" 24#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) : 51 mDestroyed(false), mTransformMatrix(NULL), mTransformCamera(NULL), mTransformMatrix3D(NULL), 52 mStaticMatrix(NULL), mAnimationMatrix(NULL) { 53 54 initFromDisplayListRenderer(recorder); 55} 56 57DisplayList::~DisplayList() { 58 mDestroyed = true; 59 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; 71 72 delete mTransformMatrix; 73 delete mTransformCamera; 74 delete mTransformMatrix3D; 75 delete mStaticMatrix; 76 delete mAnimationMatrix; 77 78 mTransformMatrix = NULL; 79 mTransformCamera = NULL; 80 mTransformMatrix3D = NULL; 81 mStaticMatrix = NULL; 82 mAnimationMatrix = NULL; 83 84 Caches& caches = Caches::getInstance(); 85 caches.unregisterFunctors(mFunctorCount); 86 caches.resourceCache.lock(); 87 88 for (size_t i = 0; i < mBitmapResources.size(); i++) { 89 caches.resourceCache.decrementRefcountLocked(mBitmapResources.itemAt(i)); 90 } 91 92 for (size_t i = 0; i < mOwnedBitmapResources.size(); i++) { 93 const SkBitmap* bitmap = mOwnedBitmapResources.itemAt(i); 94 caches.resourceCache.decrementRefcountLocked(bitmap); 95 caches.resourceCache.destructorLocked(bitmap); 96 } 97 98 for (size_t i = 0; i < mFilterResources.size(); i++) { 99 caches.resourceCache.decrementRefcountLocked(mFilterResources.itemAt(i)); 100 } 101 102 for (size_t i = 0; i < mPatchResources.size(); i++) { 103 caches.resourceCache.decrementRefcountLocked(mPatchResources.itemAt(i)); 104 } 105 106 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++) { 130 delete mPaths.itemAt(i); 131 } 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(); 140 mPatchResources.clear(); 141 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<const SkBitmap*>& bitmapResources = recorder.getBitmapResources(); 177 for (size_t i = 0; i < bitmapResources.size(); i++) { 178 const SkBitmap* resource = bitmapResources.itemAt(i); 179 mBitmapResources.add(resource); 180 caches.resourceCache.incrementRefcountLocked(resource); 181 } 182 183 const Vector<const SkBitmap*>& ownedBitmapResources = recorder.getOwnedBitmapResources(); 184 for (size_t i = 0; i < ownedBitmapResources.size(); i++) { 185 const 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 197 const Vector<const Res_png_9patch*>& patchResources = recorder.getPatchResources(); 198 for (size_t i = 0; i < patchResources.size(); i++) { 199 const Res_png_9patch* resource = patchResources.itemAt(i); 200 mPatchResources.add(resource); 201 caches.resourceCache.incrementRefcountLocked(resource); 202 } 203 204 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<const 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; 239 mClipToBounds = true; 240 mIsContainedVolume = true; 241 mProjectToContainedVolume = false; 242 mAlpha = 1; 243 mHasOverlappingRendering = true; 244 mTranslationX = 0; 245 mTranslationY = 0; 246 mTranslationZ = 0; 247 mRotation = 0; 248 mRotationX = 0; 249 mRotationY= 0; 250 mScaleX = 1; 251 mScaleY = 1; 252 mPivotX = 0; 253 mPivotY = 0; 254 mCameraDistance = 0; 255 mMatrixDirty = false; 256 mMatrixFlags = 0; 257 mPrevWidth = -1; 258 mPrevHeight = -1; 259 mWidth = 0; 260 mHeight = 0; 261 mPivotExplicitlySet = false; 262 mCaching = false; 263} 264 265size_t DisplayList::getSize() { 266 return mSize; 267} 268 269/** 270 * This function is a simplified version of replay(), where we simply retrieve and log the 271 * display list. This function should remain in sync with the replay() function. 272 */ 273void DisplayList::output(uint32_t level) { 274 ALOGD("%*sStart display list (%p, %s, render=%d)", (level - 1) * 2, "", this, 275 mName.string(), isRenderable()); 276 ALOGD("%*s%s %d", level * 2, "", "Save", 277 SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); 278 279 outputViewProperties(level); 280 int flags = DisplayListOp::kOpLogFlag_Recurse; 281 for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) { 282 mDisplayListData->displayListOps[i]->output(level, flags); 283 } 284 285 ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, mName.string()); 286} 287 288float DisplayList::getPivotX() { 289 updateMatrix(); 290 return mPivotX; 291} 292 293float DisplayList::getPivotY() { 294 updateMatrix(); 295 return mPivotY; 296} 297 298void DisplayList::updateMatrix() { 299 if (mMatrixDirty) { 300 if (!mTransformMatrix) { 301 mTransformMatrix = new SkMatrix(); 302 } 303 if (mMatrixFlags == 0 || mMatrixFlags == TRANSLATION) { 304 mTransformMatrix->reset(); 305 } else { 306 if (!mPivotExplicitlySet) { 307 if (mWidth != mPrevWidth || mHeight != mPrevHeight) { 308 mPrevWidth = mWidth; 309 mPrevHeight = mHeight; 310 mPivotX = mPrevWidth / 2.0f; 311 mPivotY = mPrevHeight / 2.0f; 312 } 313 } 314 if (!Caches::getInstance().propertyEnable3d && (mMatrixFlags & ROTATION_3D) == 0) { 315 mTransformMatrix->setTranslate(mTranslationX, mTranslationY); 316 mTransformMatrix->preRotate(mRotation, mPivotX, mPivotY); 317 mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY); 318 } else { 319 if (Caches::getInstance().propertyEnable3d) { 320 mTransform.loadTranslate(mPivotX + mTranslationX, mPivotY + mTranslationY, 321 mTranslationZ); 322 mTransform.rotate(mRotationX, 1, 0, 0); 323 mTransform.rotate(mRotationY, 0, 1, 0); 324 mTransform.rotate(mRotation, 0, 0, 1); 325 mTransform.scale(mScaleX, mScaleY, 1); 326 mTransform.translate(-mPivotX, -mPivotY); 327 } else { 328 /* TODO: support this old transform approach, based on API level */ 329 if (!mTransformCamera) { 330 mTransformCamera = new Sk3DView(); 331 mTransformMatrix3D = new SkMatrix(); 332 } 333 mTransformMatrix->reset(); 334 mTransformCamera->save(); 335 mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY); 336 mTransformCamera->rotateX(mRotationX); 337 mTransformCamera->rotateY(mRotationY); 338 mTransformCamera->rotateZ(-mRotation); 339 mTransformCamera->getMatrix(mTransformMatrix3D); 340 mTransformMatrix3D->preTranslate(-mPivotX, -mPivotY); 341 mTransformMatrix3D->postTranslate(mPivotX + mTranslationX, 342 mPivotY + mTranslationY); 343 mTransformMatrix->postConcat(*mTransformMatrix3D); 344 mTransformCamera->restore(); 345 } 346 } 347 } 348 mMatrixDirty = false; 349 } 350} 351 352void DisplayList::outputViewProperties(const int level) { 353 updateMatrix(); 354 if (mLeft != 0 || mTop != 0) { 355 ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", mLeft, mTop); 356 } 357 if (mStaticMatrix) { 358 ALOGD("%*sConcatMatrix (static) %p: " MATRIX_STRING, 359 level * 2, "", mStaticMatrix, MATRIX_ARGS(mStaticMatrix)); 360 } 361 if (mAnimationMatrix) { 362 ALOGD("%*sConcatMatrix (animation) %p: " MATRIX_STRING, 363 level * 2, "", mAnimationMatrix, MATRIX_ARGS(mAnimationMatrix)); 364 } 365 if (mMatrixFlags != 0) { 366 if (mMatrixFlags == TRANSLATION) { 367 ALOGD("%*sTranslate %f, %f", level * 2, "", mTranslationX, mTranslationY); 368 } else { 369 ALOGD("%*sConcatMatrix %p: " MATRIX_STRING, 370 level * 2, "", mTransformMatrix, MATRIX_ARGS(mTransformMatrix)); 371 } 372 } 373 374 bool clipToBoundsNeeded = mCaching ? false : mClipToBounds; 375 if (mAlpha < 1) { 376 if (mCaching) { 377 ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mAlpha); 378 } else if (!mHasOverlappingRendering) { 379 ALOGD("%*sScaleAlpha %.2f", level * 2, "", mAlpha); 380 } else { 381 int flags = SkCanvas::kHasAlphaLayer_SaveFlag; 382 if (clipToBoundsNeeded) { 383 flags |= SkCanvas::kClipToLayer_SaveFlag; 384 clipToBoundsNeeded = false; // clipping done by save layer 385 } 386 ALOGD("%*sSaveLayerAlpha %.2f, %.2f, %.2f, %.2f, %d, 0x%x", level * 2, "", 387 (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop, 388 (int)(mAlpha * 255), flags); 389 } 390 } 391 if (clipToBoundsNeeded) { 392 ALOGD("%*sClipRect %.2f, %.2f, %.2f, %.2f", level * 2, "", 0.0f, 0.0f, 393 (float) mRight - mLeft, (float) mBottom - mTop); 394 } 395} 396 397/* 398 * For property operations, we pass a savecount of 0, since the operations aren't part of the 399 * displaylist, and thus don't have to compensate for the record-time/playback-time discrepancy in 400 * base saveCount (i.e., how RestoreToCount uses saveCount + mCount) 401 */ 402#define PROPERTY_SAVECOUNT 0 403 404template <class T> 405void DisplayList::setViewProperties(OpenGLRenderer& renderer, T& handler, 406 const int level) { 407#if DEBUG_DISPLAY_LIST 408 outputViewProperties(level); 409#endif 410 updateMatrix(); 411 if (mLeft != 0 || mTop != 0) { 412 renderer.translate(mLeft, mTop); 413 } 414 if (mStaticMatrix) { 415 renderer.concatMatrix(mStaticMatrix); 416 } else if (mAnimationMatrix) { 417 renderer.concatMatrix(mAnimationMatrix); 418 } 419 if (mMatrixFlags != 0) { 420 if (mMatrixFlags == TRANSLATION) { 421 renderer.translate(mTranslationX, mTranslationY, mTranslationZ); 422 } else { 423 if (Caches::getInstance().propertyEnable3d) { 424 renderer.concatMatrix(mTransform); 425 } else { 426 renderer.concatMatrix(mTransformMatrix); 427 } 428 } 429 } 430 bool clipToBoundsNeeded = mCaching ? false : mClipToBounds; 431 if (mAlpha < 1) { 432 if (mCaching) { 433 renderer.setOverrideLayerAlpha(mAlpha); 434 } else if (!mHasOverlappingRendering) { 435 renderer.scaleAlpha(mAlpha); 436 } 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. 440 int saveFlags = SkCanvas::kHasAlphaLayer_SaveFlag; 441 if (clipToBoundsNeeded) { 442 saveFlags |= SkCanvas::kClipToLayer_SaveFlag; 443 clipToBoundsNeeded = false; // clipping done by saveLayer 444 } 445 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); 450 } 451 } 452 if (clipToBoundsNeeded) { 453 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 (Caches::getInstance().propertyEnable3d) { 478 matrix.multiply(mTransform); 479 } else { 480 mat4 temp(*mTransformMatrix); 481 matrix.multiply(temp); 482 } 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 if (mDisplayListData == NULL) return; 498 499 for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) { 500 DrawDisplayListOp* childOp = mDisplayListData->children[i]; 501 childOp->mDisplayList->computeOrderingImpl(childOp, &m3dNodes, &mat4::identity()); 502 } 503} 504 505void DisplayList::computeOrderingImpl( 506 DrawDisplayListOp* opState, 507 KeyedVector<float, Vector<DrawDisplayListOp*> >* compositedChildrenOf3dRoot, 508 const mat4* transformFrom3dRoot) { 509 510 // TODO: should avoid this calculation in most cases 511 opState->mTransformFrom3dRoot.load(*transformFrom3dRoot); 512 opState->mTransformFrom3dRoot.multiply(opState->mTransformFromParent); 513 514 if (mTranslationZ != 0.0f) { // TODO: other signals, such as custom 4x4 matrix 515 // composited layer, insert into current 3d root and flag for out of order draw 516 opState->mSkipInOrderDraw = true; 517 518 Vector3 pivot(mPivotX, mPivotY, 0.0f); 519 mat4 totalTransform(opState->mTransformFrom3dRoot); 520 applyViewPropertyTransforms(totalTransform); 521 totalTransform.mapPoint3d(pivot); 522 const float key = pivot.z; 523 524 if (compositedChildrenOf3dRoot->indexOfKey(key) < 0) { 525 compositedChildrenOf3dRoot->add(key, Vector<DrawDisplayListOp*>()); 526 } 527 compositedChildrenOf3dRoot->editValueFor(key).push(opState); 528 } else { 529 // standard in order draw 530 opState->mSkipInOrderDraw = false; 531 } 532 533 m3dNodes.clear(); 534 if (mIsContainedVolume) { 535 // create a new 3d space for children by separating their ordering 536 compositedChildrenOf3dRoot = &m3dNodes; 537 transformFrom3dRoot = &mat4::identity(); 538 } else { 539 transformFrom3dRoot = &(opState->mTransformFrom3dRoot); 540 } 541 542 if (mDisplayListData != NULL && mDisplayListData->children.size() > 0) { 543 for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) { 544 DrawDisplayListOp* childOp = mDisplayListData->children[i]; 545 childOp->mDisplayList->computeOrderingImpl(childOp, 546 compositedChildrenOf3dRoot, transformFrom3dRoot); 547 } 548 } 549} 550 551class DeferOperationHandler { 552public: 553 DeferOperationHandler(DeferStateStruct& deferStruct, int level) 554 : mDeferStruct(deferStruct), mLevel(level) {} 555 inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) { 556 operation->defer(mDeferStruct, saveCount, mLevel, clipToBounds); 557 } 558 inline LinearAllocator& allocator() { return *(mDeferStruct.mAllocator); } 559 560private: 561 DeferStateStruct& mDeferStruct; 562 const int mLevel; 563}; 564 565void DisplayList::defer(DeferStateStruct& deferStruct, const int level) { 566 DeferOperationHandler handler(deferStruct, level); 567 iterate<DeferOperationHandler>(deferStruct.mRenderer, handler, level); 568} 569 570class ReplayOperationHandler { 571public: 572 ReplayOperationHandler(ReplayStateStruct& replayStruct, int level) 573 : mReplayStruct(replayStruct), mLevel(level) {} 574 inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) { 575#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS 576 mReplayStruct.mRenderer.eventMark(operation->name()); 577#endif 578 operation->replay(mReplayStruct, saveCount, mLevel, clipToBounds); 579 } 580 inline LinearAllocator& allocator() { return *(mReplayStruct.mAllocator); } 581 582private: 583 ReplayStateStruct& mReplayStruct; 584 const int mLevel; 585}; 586 587void DisplayList::replay(ReplayStateStruct& replayStruct, const int level) { 588 ReplayOperationHandler handler(replayStruct, level); 589 590 replayStruct.mRenderer.startMark(mName.string()); 591 iterate<ReplayOperationHandler>(replayStruct.mRenderer, handler, level); 592 replayStruct.mRenderer.endMark(); 593 594 DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", level * 2, "", this, mName.string(), 595 replayStruct.mDrawGlStatus); 596} 597 598template <class T> 599void DisplayList::iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& renderer, 600 T& handler, const int level) { 601 if (m3dNodes.size() == 0 || 602 (mode == kNegativeZChildren && m3dNodes.keyAt(0) > 0.0f) || 603 (mode == kPositiveZChildren && m3dNodes.keyAt(m3dNodes.size() - 1) < 0.0f)) { 604 // nothing to draw 605 return; 606 } 607 608 LinearAllocator& alloc = handler.allocator(); 609 ClipRectOp* op = new (alloc) ClipRectOp(0, 0, mWidth, mHeight, 610 SkRegion::kIntersect_Op); // clip to 3d root bounds for now 611 handler(op, PROPERTY_SAVECOUNT, mClipToBounds); 612 int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); 613 614 for (size_t i = 0; i < m3dNodes.size(); i++) { 615 const float zValue = m3dNodes.keyAt(i); 616 617 if (mode == kPositiveZChildren && zValue < 0.0f) continue; 618 if (mode == kNegativeZChildren && zValue > 0.0f) break; 619 620 const Vector<DrawDisplayListOp*>& nodesAtZ = m3dNodes[i]; 621 for (size_t j = 0; j < nodesAtZ.size(); j++) { 622 DrawDisplayListOp* op = nodesAtZ[j]; 623 if (mode == kPositiveZChildren) { 624 /* draw shadow on renderer with parent matrix applied, passing in the child's total matrix 625 * 626 * TODO: 627 * -determine and pass background shape (and possibly drawable alpha) 628 * -view must opt-in to shadows 629 * -consider shadows for other content 630 */ 631 mat4 shadowMatrix(op->mTransformFrom3dRoot); 632 op->mDisplayList->applyViewPropertyTransforms(shadowMatrix); 633 DisplayListOp* shadowOp = new (alloc) DrawShadowOp(shadowMatrix, op->mDisplayList->mAlpha, 634 op->mDisplayList->getWidth(), op->mDisplayList->getHeight()); 635 handler(shadowOp, PROPERTY_SAVECOUNT, mClipToBounds); 636 } 637 638 renderer.concatMatrix(op->mTransformFrom3dRoot); 639 op->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone 640 handler(op, renderer.getSaveCount() - 1, mClipToBounds); 641 op->mSkipInOrderDraw = true; 642 } 643 } 644 handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, mClipToBounds); 645} 646 647/** 648 * This function serves both defer and replay modes, and will organize the displayList's component 649 * operations for a single frame: 650 * 651 * Every 'simple' state operation that affects just the matrix and alpha (or other factors of 652 * DeferredDisplayState) may be issued directly to the renderer, but complex operations (with custom 653 * defer logic) and operations in displayListOps are issued through the 'handler' which handles the 654 * defer vs replay logic, per operation 655 */ 656template <class T> 657void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level) { 658 if (CC_UNLIKELY(mDestroyed)) { // temporary debug logging 659 ALOGW("Error: %s is drawing after destruction, size %d", getName(), mSize); 660 CRASH(); 661 } 662 if (mSize == 0 || mAlpha <= 0) { 663 DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, mName.string()); 664 return; 665 } 666 667#if DEBUG_DISPLAY_LIST 668 Rect* clipRect = renderer.getClipRect(); 669 DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.0f, %.0f, %.0f", 670 level * 2, "", this, mName.string(), clipRect->left, clipRect->top, 671 clipRect->right, clipRect->bottom); 672#endif 673 674 LinearAllocator& alloc = handler.allocator(); 675 int restoreTo = renderer.getSaveCount(); 676 handler(new (alloc) SaveOp(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag), 677 PROPERTY_SAVECOUNT, mClipToBounds); 678 679 DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "", 680 SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo); 681 682 setViewProperties<T>(renderer, handler, level + 1); 683 684 bool quickRejected = mClipToBounds && renderer.quickRejectConservative(0, 0, mWidth, mHeight); 685 if (!quickRejected) { 686 // for 3d root, draw children with negative z values 687 iterate3dChildren(kNegativeZChildren, renderer, handler, level); 688 689 DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance(); 690 const int saveCountOffset = renderer.getSaveCount() - 1; 691 for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) { 692 DisplayListOp *op = mDisplayListData->displayListOps[i]; 693 694#if DEBUG_DISPLAY_LIST 695 op->output(level + 1); 696#endif 697 698 logBuffer.writeCommand(level, op->name()); 699 handler(op, saveCountOffset, mClipToBounds); 700 } 701 702 // for 3d root, draw children with positive z values 703 iterate3dChildren(kPositiveZChildren, renderer, handler, level); 704 } 705 706 DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo); 707 handler(new (alloc) RestoreToCountOp(restoreTo), 708 PROPERTY_SAVECOUNT, mClipToBounds); 709 renderer.setOverrideLayerAlpha(1.0f); 710} 711 712}; // namespace uirenderer 713}; // namespace android 714