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