DisplayList.cpp revision eea6ef9c767c734797912022113191dd255c4ae6
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#include <algorithm> 21 22#include <utils/Trace.h> 23 24#include "Debug.h" 25#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() : 52 mDisplayListData(0), mDestroyed(false), mTransformMatrix(NULL), mTransformCamera(NULL), 53 mTransformMatrix3D(NULL), mStaticMatrix(NULL), mAnimationMatrix(NULL) { 54 55 mLeft = 0; 56 mTop = 0; 57 mRight = 0; 58 mBottom = 0; 59 mClipToBounds = true; 60 mIsolatedZVolume = true; 61 mProjectBackwards = false; 62 mProjectionReceiver = false; 63 mOutline.rewind(); 64 mClipToOutline = false; 65 mCastsShadow = false; 66 mUsesGlobalCamera = false; 67 mAlpha = 1; 68 mHasOverlappingRendering = true; 69 mTranslationX = 0; 70 mTranslationY = 0; 71 mTranslationZ = 0; 72 mRotation = 0; 73 mRotationX = 0; 74 mRotationY= 0; 75 mScaleX = 1; 76 mScaleY = 1; 77 mPivotX = 0; 78 mPivotY = 0; 79 mCameraDistance = 0; 80 mMatrixDirty = false; 81 mMatrixFlags = 0; 82 mPrevWidth = -1; 83 mPrevHeight = -1; 84 mWidth = 0; 85 mHeight = 0; 86 mPivotExplicitlySet = false; 87 mCaching = false; 88} 89 90DisplayList::~DisplayList() { 91 LOG_ALWAYS_FATAL_IF(mDestroyed, "Double destroyed DisplayList %p", this); 92 93 mDestroyed = true; 94 delete mDisplayListData; 95 delete mTransformMatrix; 96 delete mTransformCamera; 97 delete mTransformMatrix3D; 98 delete mStaticMatrix; 99 delete mAnimationMatrix; 100} 101 102void DisplayList::destroyDisplayListDeferred(DisplayList* displayList) { 103 if (displayList) { 104 DISPLAY_LIST_LOGD("Deferring display list destruction"); 105 Caches::getInstance().deleteDisplayListDeferred(displayList); 106 } 107} 108 109void DisplayList::setData(DisplayListData* data) { 110 delete mDisplayListData; 111 mDisplayListData = data; 112} 113 114/** 115 * This function is a simplified version of replay(), where we simply retrieve and log the 116 * display list. This function should remain in sync with the replay() function. 117 */ 118void DisplayList::output(uint32_t level) { 119 ALOGD("%*sStart display list (%p, %s, render=%d)", (level - 1) * 2, "", this, 120 mName.string(), isRenderable()); 121 ALOGD("%*s%s %d", level * 2, "", "Save", 122 SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); 123 124 outputViewProperties(level); 125 int flags = DisplayListOp::kOpLogFlag_Recurse; 126 for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) { 127 mDisplayListData->displayListOps[i]->output(level, flags); 128 } 129 130 ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, mName.string()); 131} 132 133float DisplayList::getPivotX() { 134 updateMatrix(); 135 return mPivotX; 136} 137 138float DisplayList::getPivotY() { 139 updateMatrix(); 140 return mPivotY; 141} 142 143void DisplayList::updateMatrix() { 144 if (mMatrixDirty) { 145 // NOTE: mTransformMatrix won't be up to date if a DisplayList goes from a complex transform 146 // to a pure translate. This is safe because the matrix isn't read in pure translate cases. 147 if (mMatrixFlags && mMatrixFlags != TRANSLATION) { 148 if (!mTransformMatrix) { 149 // only allocate a matrix if we have a complex transform 150 mTransformMatrix = new Matrix4(); 151 } 152 if (!mPivotExplicitlySet) { 153 if (mWidth != mPrevWidth || mHeight != mPrevHeight) { 154 mPrevWidth = mWidth; 155 mPrevHeight = mHeight; 156 mPivotX = mPrevWidth / 2.0f; 157 mPivotY = mPrevHeight / 2.0f; 158 } 159 } 160 const bool perspectiveEnabled = Caches::getInstance().propertyEnable3d; 161 if (!perspectiveEnabled && (mMatrixFlags & ROTATION_3D) == 0) { 162 mTransformMatrix->loadTranslate( 163 mPivotX + mTranslationX, 164 mPivotY + mTranslationY, 165 0); 166 mTransformMatrix->rotate(mRotation, 0, 0, 1); 167 mTransformMatrix->scale(mScaleX, mScaleY, 1); 168 mTransformMatrix->translate(-mPivotX, -mPivotY); 169 } else { 170 if (perspectiveEnabled) { 171 mTransformMatrix->loadTranslate( 172 mPivotX + mTranslationX, 173 mPivotY + mTranslationY, 174 mTranslationZ); 175 mTransformMatrix->rotate(mRotationX, 1, 0, 0); 176 mTransformMatrix->rotate(mRotationY, 0, 1, 0); 177 mTransformMatrix->rotate(mRotation, 0, 0, 1); 178 mTransformMatrix->scale(mScaleX, mScaleY, 1); 179 mTransformMatrix->translate(-mPivotX, -mPivotY); 180 } else { 181 /* TODO: support this old transform approach, based on API level */ 182 if (!mTransformCamera) { 183 mTransformCamera = new Sk3DView(); 184 mTransformMatrix3D = new SkMatrix(); 185 } 186 SkMatrix transformMatrix; 187 transformMatrix.reset(); 188 mTransformCamera->save(); 189 transformMatrix.preScale(mScaleX, mScaleY, mPivotX, mPivotY); 190 mTransformCamera->rotateX(mRotationX); 191 mTransformCamera->rotateY(mRotationY); 192 mTransformCamera->rotateZ(-mRotation); 193 mTransformCamera->getMatrix(mTransformMatrix3D); 194 mTransformMatrix3D->preTranslate(-mPivotX, -mPivotY); 195 mTransformMatrix3D->postTranslate(mPivotX + mTranslationX, 196 mPivotY + mTranslationY); 197 transformMatrix.postConcat(*mTransformMatrix3D); 198 mTransformCamera->restore(); 199 200 mTransformMatrix->load(transformMatrix); 201 } 202 } 203 } 204 mMatrixDirty = false; 205 } 206} 207 208void DisplayList::outputViewProperties(const int level) { 209 updateMatrix(); 210 if (mLeft != 0 || mTop != 0) { 211 ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", mLeft, mTop); 212 } 213 if (mStaticMatrix) { 214 ALOGD("%*sConcatMatrix (static) %p: " SK_MATRIX_STRING, 215 level * 2, "", mStaticMatrix, SK_MATRIX_ARGS(mStaticMatrix)); 216 } 217 if (mAnimationMatrix) { 218 ALOGD("%*sConcatMatrix (animation) %p: " SK_MATRIX_STRING, 219 level * 2, "", mAnimationMatrix, SK_MATRIX_ARGS(mAnimationMatrix)); 220 } 221 if (mMatrixFlags != 0) { 222 if (mMatrixFlags == TRANSLATION) { 223 ALOGD("%*sTranslate %.2f, %.2f, %.2f", 224 level * 2, "", mTranslationX, mTranslationY, mTranslationZ); 225 } else { 226 ALOGD("%*sConcatMatrix %p: " MATRIX_4_STRING, 227 level * 2, "", mTransformMatrix, MATRIX_4_ARGS(mTransformMatrix)); 228 } 229 } 230 231 bool clipToBoundsNeeded = mCaching ? false : mClipToBounds; 232 if (mAlpha < 1) { 233 if (mCaching) { 234 ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mAlpha); 235 } else if (!mHasOverlappingRendering) { 236 ALOGD("%*sScaleAlpha %.2f", level * 2, "", mAlpha); 237 } else { 238 int flags = SkCanvas::kHasAlphaLayer_SaveFlag; 239 if (clipToBoundsNeeded) { 240 flags |= SkCanvas::kClipToLayer_SaveFlag; 241 clipToBoundsNeeded = false; // clipping done by save layer 242 } 243 ALOGD("%*sSaveLayerAlpha %.2f, %.2f, %.2f, %.2f, %d, 0x%x", level * 2, "", 244 (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop, 245 (int)(mAlpha * 255), flags); 246 } 247 } 248 if (clipToBoundsNeeded) { 249 ALOGD("%*sClipRect %.2f, %.2f, %.2f, %.2f", level * 2, "", 0.0f, 0.0f, 250 (float) mRight - mLeft, (float) mBottom - mTop); 251 } 252} 253 254/* 255 * For property operations, we pass a savecount of 0, since the operations aren't part of the 256 * displaylist, and thus don't have to compensate for the record-time/playback-time discrepancy in 257 * base saveCount (i.e., how RestoreToCount uses saveCount + mCount) 258 */ 259#define PROPERTY_SAVECOUNT 0 260 261template <class T> 262void DisplayList::setViewProperties(OpenGLRenderer& renderer, T& handler, 263 const int level) { 264#if DEBUG_DISPLAY_LIST 265 outputViewProperties(level); 266#endif 267 updateMatrix(); 268 if (mLeft != 0 || mTop != 0) { 269 renderer.translate(mLeft, mTop); 270 } 271 if (mStaticMatrix) { 272 renderer.concatMatrix(mStaticMatrix); 273 } else if (mAnimationMatrix) { 274 renderer.concatMatrix(mAnimationMatrix); 275 } 276 if (mMatrixFlags != 0) { 277 if (mMatrixFlags == TRANSLATION) { 278 renderer.translate(mTranslationX, mTranslationY, 279 Caches::getInstance().propertyEnable3d ? mTranslationZ : 0.0f); // TODO: necessary? 280 } else { 281 renderer.concatMatrix(*mTransformMatrix); 282 } 283 } 284 bool clipToBoundsNeeded = mCaching ? false : mClipToBounds; 285 if (mAlpha < 1) { 286 if (mCaching) { 287 renderer.setOverrideLayerAlpha(mAlpha); 288 } else if (!mHasOverlappingRendering) { 289 renderer.scaleAlpha(mAlpha); 290 } else { 291 // TODO: should be able to store the size of a DL at record time and not 292 // have to pass it into this call. In fact, this information might be in the 293 // location/size info that we store with the new native transform data. 294 int saveFlags = SkCanvas::kHasAlphaLayer_SaveFlag; 295 if (clipToBoundsNeeded) { 296 saveFlags |= SkCanvas::kClipToLayer_SaveFlag; 297 clipToBoundsNeeded = false; // clipping done by saveLayer 298 } 299 300 SaveLayerOp* op = new (handler.allocator()) SaveLayerOp( 301 0, 0, mRight - mLeft, mBottom - mTop, mAlpha * 255, saveFlags); 302 handler(op, PROPERTY_SAVECOUNT, mClipToBounds); 303 } 304 } 305 if (clipToBoundsNeeded) { 306 ClipRectOp* op = new (handler.allocator()) ClipRectOp(0, 0, 307 mRight - mLeft, mBottom - mTop, SkRegion::kIntersect_Op); 308 handler(op, PROPERTY_SAVECOUNT, mClipToBounds); 309 } 310 if (CC_UNLIKELY(mClipToOutline && !mOutline.isEmpty())) { 311 ClipPathOp* op = new (handler.allocator()) ClipPathOp(&mOutline, SkRegion::kIntersect_Op); 312 handler(op, PROPERTY_SAVECOUNT, mClipToBounds); 313 } 314} 315 316/** 317 * Apply property-based transformations to input matrix 318 */ 319void DisplayList::applyViewPropertyTransforms(mat4& matrix) { 320 if (mLeft != 0 || mTop != 0) { 321 matrix.translate(mLeft, mTop); 322 } 323 if (mStaticMatrix) { 324 mat4 stat(*mStaticMatrix); 325 matrix.multiply(stat); 326 } else if (mAnimationMatrix) { 327 mat4 anim(*mAnimationMatrix); 328 matrix.multiply(anim); 329 } 330 if (mMatrixFlags != 0) { 331 updateMatrix(); 332 if (mMatrixFlags == TRANSLATION) { 333 matrix.translate(mTranslationX, mTranslationY, mTranslationZ); 334 } else { 335 matrix.multiply(*mTransformMatrix); 336 } 337 } 338} 339 340/** 341 * Organizes the DisplayList hierarchy to prepare for Z-based draw order. 342 * 343 * This should be called before a call to defer() or drawDisplayList() 344 * 345 * Each DisplayList that serves as a 3d root builds its list of composited children, 346 * which are flagged to not draw in the standard draw loop. 347 */ 348void DisplayList::computeOrdering() { 349 ATRACE_CALL(); 350 m3dNodes.clear(); 351 mProjectedNodes.clear(); 352 353 // TODO: create temporary DDLOp and call computeOrderingImpl on top DisplayList so that 354 // transform properties are applied correctly to top level children 355 if (mDisplayListData == NULL) return; 356 for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) { 357 DrawDisplayListOp* childOp = mDisplayListData->children[i]; 358 childOp->mDisplayList->computeOrderingImpl(childOp, 359 &m3dNodes, &mat4::identity(), 360 &mProjectedNodes, &mat4::identity()); 361 } 362} 363 364void DisplayList::computeOrderingImpl( 365 DrawDisplayListOp* opState, 366 Vector<ZDrawDisplayListOpPair>* compositedChildrenOf3dRoot, 367 const mat4* transformFrom3dRoot, 368 Vector<DrawDisplayListOp*>* compositedChildrenOfProjectionSurface, 369 const mat4* transformFromProjectionSurface) { 370 m3dNodes.clear(); 371 mProjectedNodes.clear(); 372 if (mDisplayListData == NULL || mDisplayListData->isEmpty()) return; 373 374 // TODO: should avoid this calculation in most cases 375 // TODO: just calculate single matrix, down to all leaf composited elements 376 Matrix4 localTransformFrom3dRoot(*transformFrom3dRoot); 377 localTransformFrom3dRoot.multiply(opState->mTransformFromParent); 378 Matrix4 localTransformFromProjectionSurface(*transformFromProjectionSurface); 379 localTransformFromProjectionSurface.multiply(opState->mTransformFromParent); 380 381 if (mTranslationZ != 0.0f) { // TODO: other signals for 3d compositing, such as custom matrix4 382 // composited 3d layer, flag for out of order draw and save matrix... 383 opState->mSkipInOrderDraw = true; 384 opState->mTransformFromCompositingAncestor.load(localTransformFrom3dRoot); 385 386 // ... and insert into current 3d root, keyed with pivot z for later sorting 387 Vector3 pivot(mPivotX, mPivotY, 0.0f); 388 mat4 totalTransform(localTransformFrom3dRoot); 389 applyViewPropertyTransforms(totalTransform); 390 totalTransform.mapPoint3d(pivot); 391 compositedChildrenOf3dRoot->add(ZDrawDisplayListOpPair(pivot.z, opState)); 392 } else if (mProjectBackwards) { 393 // composited projectee, flag for out of order draw, save matrix, and store in proj surface 394 opState->mSkipInOrderDraw = true; 395 opState->mTransformFromCompositingAncestor.load(localTransformFromProjectionSurface); 396 compositedChildrenOfProjectionSurface->add(opState); 397 } else { 398 // standard in order draw 399 opState->mSkipInOrderDraw = false; 400 } 401 402 if (mDisplayListData->children.size() > 0) { 403 if (mIsolatedZVolume) { 404 // create a new 3d space for descendents by collecting them 405 compositedChildrenOf3dRoot = &m3dNodes; 406 transformFrom3dRoot = &mat4::identity(); 407 } else { 408 applyViewPropertyTransforms(localTransformFrom3dRoot); 409 transformFrom3dRoot = &localTransformFrom3dRoot; 410 } 411 412 const bool isProjectionReceiver = mDisplayListData->projectionReceiveIndex >= 0; 413 bool haveAppliedPropertiesToProjection = false; 414 for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) { 415 DrawDisplayListOp* childOp = mDisplayListData->children[i]; 416 DisplayList* child = childOp->mDisplayList; 417 418 Vector<DrawDisplayListOp*>* projectionChildren = NULL; 419 const mat4* projectionTransform = NULL; 420 if (isProjectionReceiver && !child->mProjectBackwards) { 421 // if receiving projections, collect projecting descendent 422 423 // Note that if a direct descendent is projecting backwards, we pass it's 424 // grandparent projection collection, since it shouldn't project onto it's 425 // parent, where it will already be drawing. 426 projectionChildren = &mProjectedNodes; 427 projectionTransform = &mat4::identity(); 428 } else { 429 if (!haveAppliedPropertiesToProjection) { 430 applyViewPropertyTransforms(localTransformFromProjectionSurface); 431 haveAppliedPropertiesToProjection = true; 432 } 433 projectionChildren = compositedChildrenOfProjectionSurface; 434 projectionTransform = &localTransformFromProjectionSurface; 435 } 436 child->computeOrderingImpl(childOp, 437 compositedChildrenOf3dRoot, transformFrom3dRoot, 438 projectionChildren, projectionTransform); 439 } 440 } 441 442} 443 444class DeferOperationHandler { 445public: 446 DeferOperationHandler(DeferStateStruct& deferStruct, int level) 447 : mDeferStruct(deferStruct), mLevel(level) {} 448 inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) { 449 operation->defer(mDeferStruct, saveCount, mLevel, clipToBounds); 450 } 451 inline LinearAllocator& allocator() { return *(mDeferStruct.mAllocator); } 452 453private: 454 DeferStateStruct& mDeferStruct; 455 const int mLevel; 456}; 457 458void DisplayList::defer(DeferStateStruct& deferStruct, const int level) { 459 DeferOperationHandler handler(deferStruct, level); 460 iterate<DeferOperationHandler>(deferStruct.mRenderer, handler, level); 461} 462 463class ReplayOperationHandler { 464public: 465 ReplayOperationHandler(ReplayStateStruct& replayStruct, int level) 466 : mReplayStruct(replayStruct), mLevel(level) {} 467 inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) { 468#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS 469 mReplayStruct.mRenderer.eventMark(operation->name()); 470#endif 471 operation->replay(mReplayStruct, saveCount, mLevel, clipToBounds); 472 } 473 inline LinearAllocator& allocator() { return *(mReplayStruct.mAllocator); } 474 475private: 476 ReplayStateStruct& mReplayStruct; 477 const int mLevel; 478}; 479 480void DisplayList::replay(ReplayStateStruct& replayStruct, const int level) { 481 ReplayOperationHandler handler(replayStruct, level); 482 483 replayStruct.mRenderer.startMark(mName.string()); 484 iterate<ReplayOperationHandler>(replayStruct.mRenderer, handler, level); 485 replayStruct.mRenderer.endMark(); 486 487 DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", level * 2, "", this, mName.string(), 488 replayStruct.mDrawGlStatus); 489} 490 491template <class T> 492void DisplayList::iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& renderer, 493 T& handler, const int level) { 494 if (m3dNodes.size() == 0 || 495 (mode == kNegativeZChildren && m3dNodes[0].key > 0.0f) || 496 (mode == kPositiveZChildren && m3dNodes[m3dNodes.size() - 1].key < 0.0f)) { 497 // no 3d children to draw 498 return; 499 } 500 501 int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); 502 LinearAllocator& alloc = handler.allocator(); 503 ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, mWidth, mHeight, 504 SkRegion::kIntersect_Op); // clip to 3d root bounds for now 505 handler(clipOp, PROPERTY_SAVECOUNT, mClipToBounds); 506 507 for (size_t i = 0; i < m3dNodes.size(); i++) { 508 const float zValue = m3dNodes[i].key; 509 DrawDisplayListOp* childOp = m3dNodes[i].value; 510 511 if (mode == kPositiveZChildren && zValue < 0.0f) continue; 512 if (mode == kNegativeZChildren && zValue > 0.0f) break; 513 514 DisplayList* child = childOp->mDisplayList; 515 if (mode == kPositiveZChildren && zValue > 0.0f 516 && child->mCastsShadow && child->mAlpha > 0.0f) { 517 /* draw shadow with parent matrix applied, passing in the child's total matrix 518 * TODO: consider depth in more complex scenarios (neg z, added shadow depth) 519 */ 520 mat4 shadowMatrix(childOp->mTransformFromCompositingAncestor); 521 child->applyViewPropertyTransforms(shadowMatrix); 522 523 DisplayListOp* shadowOp = new (alloc) DrawShadowOp(shadowMatrix, 524 child->mAlpha, &(child->mOutline), child->mWidth, child->mHeight); 525 handler(shadowOp, PROPERTY_SAVECOUNT, mClipToBounds); 526 } 527 528 renderer.concatMatrix(childOp->mTransformFromCompositingAncestor); 529 childOp->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone 530 handler(childOp, renderer.getSaveCount() - 1, mClipToBounds); 531 childOp->mSkipInOrderDraw = true; 532 } 533 handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, mClipToBounds); 534} 535 536template <class T> 537void DisplayList::iterateProjectedChildren(OpenGLRenderer& renderer, T& handler, const int level) { 538 int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); 539 LinearAllocator& alloc = handler.allocator(); 540 ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, mWidth, mHeight, 541 SkRegion::kReplace_Op); // clip to projection surface root bounds 542 handler(clipOp, PROPERTY_SAVECOUNT, mClipToBounds); 543 544 for (size_t i = 0; i < mProjectedNodes.size(); i++) { 545 DrawDisplayListOp* childOp = mProjectedNodes[i]; 546 547 // matrix save, concat, and restore can be done safely without allocating operations 548 int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag); 549 renderer.concatMatrix(childOp->mTransformFromCompositingAncestor); 550 childOp->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone 551 handler(childOp, renderer.getSaveCount() - 1, mClipToBounds); 552 childOp->mSkipInOrderDraw = true; 553 renderer.restoreToCount(restoreTo); 554 } 555 handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, mClipToBounds); 556} 557 558/** 559 * This function serves both defer and replay modes, and will organize the displayList's component 560 * operations for a single frame: 561 * 562 * Every 'simple' state operation that affects just the matrix and alpha (or other factors of 563 * DeferredDisplayState) may be issued directly to the renderer, but complex operations (with custom 564 * defer logic) and operations in displayListOps are issued through the 'handler' which handles the 565 * defer vs replay logic, per operation 566 */ 567template <class T> 568void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level) { 569 if (CC_UNLIKELY(mDestroyed)) { // temporary debug logging 570 ALOGW("Error: %s is drawing after destruction", getName()); 571 CRASH(); 572 } 573 if (mDisplayListData->isEmpty() || mAlpha <= 0) { 574 DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, mName.string()); 575 return; 576 } 577 578#if DEBUG_DISPLAY_LIST 579 Rect* clipRect = renderer.getClipRect(); 580 DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.0f, %.0f, %.0f", 581 level * 2, "", this, mName.string(), clipRect->left, clipRect->top, 582 clipRect->right, clipRect->bottom); 583#endif 584 585 LinearAllocator& alloc = handler.allocator(); 586 int restoreTo = renderer.getSaveCount(); 587 handler(new (alloc) SaveOp(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag), 588 PROPERTY_SAVECOUNT, mClipToBounds); 589 590 DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "", 591 SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo); 592 593 setViewProperties<T>(renderer, handler, level + 1); 594 595 bool quickRejected = mClipToBounds && renderer.quickRejectConservative(0, 0, mWidth, mHeight); 596 if (!quickRejected) { 597 // Z sort 3d children (stable-ness makes z compare fall back to standard drawing order) 598 std::stable_sort(m3dNodes.begin(), m3dNodes.end()); 599 600 // for 3d root, draw children with negative z values 601 iterate3dChildren(kNegativeZChildren, renderer, handler, level); 602 603 DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance(); 604 const int saveCountOffset = renderer.getSaveCount() - 1; 605 const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex; 606 for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) { 607 DisplayListOp *op = mDisplayListData->displayListOps[i]; 608 609#if DEBUG_DISPLAY_LIST 610 op->output(level + 1); 611#endif 612 613 logBuffer.writeCommand(level, op->name()); 614 handler(op, saveCountOffset, mClipToBounds); 615 616 if (CC_UNLIKELY(i == projectionReceiveIndex && mProjectedNodes.size() > 0)) { 617 iterateProjectedChildren(renderer, handler, level); 618 } 619 } 620 621 // for 3d root, draw children with positive z values 622 iterate3dChildren(kPositiveZChildren, renderer, handler, level); 623 } 624 625 DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo); 626 handler(new (alloc) RestoreToCountOp(restoreTo), 627 PROPERTY_SAVECOUNT, mClipToBounds); 628 renderer.setOverrideLayerAlpha(1.0f); 629} 630 631void DisplayListData::cleanupResources() { 632 Caches& caches = Caches::getInstance(); 633 caches.unregisterFunctors(functorCount); 634 caches.resourceCache.lock(); 635 636 for (size_t i = 0; i < bitmapResources.size(); i++) { 637 caches.resourceCache.decrementRefcountLocked(bitmapResources.itemAt(i)); 638 } 639 640 for (size_t i = 0; i < ownedBitmapResources.size(); i++) { 641 const SkBitmap* bitmap = ownedBitmapResources.itemAt(i); 642 caches.resourceCache.decrementRefcountLocked(bitmap); 643 caches.resourceCache.destructorLocked(bitmap); 644 } 645 646 for (size_t i = 0; i < patchResources.size(); i++) { 647 caches.resourceCache.decrementRefcountLocked(patchResources.itemAt(i)); 648 } 649 650 for (size_t i = 0; i < shaders.size(); i++) { 651 caches.resourceCache.decrementRefcountLocked(shaders.itemAt(i)); 652 caches.resourceCache.destructorLocked(shaders.itemAt(i)); 653 } 654 655 for (size_t i = 0; i < sourcePaths.size(); i++) { 656 caches.resourceCache.decrementRefcountLocked(sourcePaths.itemAt(i)); 657 } 658 659 for (size_t i = 0; i < layers.size(); i++) { 660 caches.resourceCache.decrementRefcountLocked(layers.itemAt(i)); 661 } 662 663 caches.resourceCache.unlock(); 664 665 for (size_t i = 0; i < paints.size(); i++) { 666 delete paints.itemAt(i); 667 } 668 669 for (size_t i = 0; i < regions.size(); i++) { 670 delete regions.itemAt(i); 671 } 672 673 for (size_t i = 0; i < paths.size(); i++) { 674 delete paths.itemAt(i); 675 } 676 677 for (size_t i = 0; i < matrices.size(); i++) { 678 delete matrices.itemAt(i); 679 } 680 681 bitmapResources.clear(); 682 ownedBitmapResources.clear(); 683 patchResources.clear(); 684 shaders.clear(); 685 sourcePaths.clear(); 686 paints.clear(); 687 regions.clear(); 688 paths.clear(); 689 matrices.clear(); 690 layers.clear(); 691} 692 693}; // namespace uirenderer 694}; // namespace android 695