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