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