DisplayList.cpp revision e18264b079481a244b30e3f71012c53bbd861f92
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() : 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 90RenderNode::~RenderNode() { 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 RenderNode::destroyDisplayListDeferred(RenderNode* displayList) { 103 if (displayList) { 104 DISPLAY_LIST_LOGD("Deferring display list destruction"); 105 Caches::getInstance().deleteDisplayListDeferred(displayList); 106 } 107} 108 109void RenderNode::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 RenderNode::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 RenderNode::getPivotX() { 137 updateMatrix(); 138 return mPivotX; 139} 140 141float RenderNode::getPivotY() { 142 updateMatrix(); 143 return mPivotY; 144} 145 146void RenderNode::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 RenderNode::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 RenderNode::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 * 308 * If true3dTransform is set to true, the transform applied to the input matrix will use true 4x4 309 * matrix computation instead of the Skia 3x3 matrix + camera hackery. 310 */ 311void RenderNode::applyViewPropertyTransforms(mat4& matrix, bool true3dTransform) { 312 if (mLeft != 0 || mTop != 0) { 313 matrix.translate(mLeft, mTop); 314 } 315 if (mStaticMatrix) { 316 mat4 stat(*mStaticMatrix); 317 matrix.multiply(stat); 318 } else if (mAnimationMatrix) { 319 mat4 anim(*mAnimationMatrix); 320 matrix.multiply(anim); 321 } 322 if (mMatrixFlags != 0) { 323 updateMatrix(); 324 if (mMatrixFlags == TRANSLATION) { 325 matrix.translate(mTranslationX, mTranslationY, 326 true3dTransform ? mTranslationZ : 0.0f); 327 } else { 328 if (!true3dTransform) { 329 matrix.multiply(*mTransformMatrix); 330 } else { 331 mat4 true3dMat; 332 true3dMat.loadTranslate( 333 mPivotX + mTranslationX, 334 mPivotY + mTranslationY, 335 mTranslationZ); 336 true3dMat.rotate(mRotationX, 1, 0, 0); 337 true3dMat.rotate(mRotationY, 0, 1, 0); 338 true3dMat.rotate(mRotation, 0, 0, 1); 339 true3dMat.scale(mScaleX, mScaleY, 1); 340 true3dMat.translate(-mPivotX, -mPivotY); 341 342 matrix.multiply(true3dMat); 343 } 344 } 345 } 346} 347 348/** 349 * Organizes the DisplayList hierarchy to prepare for background projection reordering. 350 * 351 * This should be called before a call to defer() or drawDisplayList() 352 * 353 * Each DisplayList that serves as a 3d root builds its list of composited children, 354 * which are flagged to not draw in the standard draw loop. 355 */ 356void RenderNode::computeOrdering() { 357 ATRACE_CALL(); 358 mProjectedNodes.clear(); 359 360 // TODO: create temporary DDLOp and call computeOrderingImpl on top DisplayList so that 361 // transform properties are applied correctly to top level children 362 if (mDisplayListData == NULL) return; 363 for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) { 364 DrawDisplayListOp* childOp = mDisplayListData->children[i]; 365 childOp->mDisplayList->computeOrderingImpl(childOp, 366 &mProjectedNodes, &mat4::identity()); 367 } 368} 369 370void RenderNode::computeOrderingImpl( 371 DrawDisplayListOp* opState, 372 Vector<DrawDisplayListOp*>* compositedChildrenOfProjectionSurface, 373 const mat4* transformFromProjectionSurface) { 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 localTransformFromProjectionSurface(*transformFromProjectionSurface); 380 localTransformFromProjectionSurface.multiply(opState->mTransformFromParent); 381 382 if (mProjectBackwards) { 383 // composited projectee, flag for out of order draw, save matrix, and store in proj surface 384 opState->mSkipInOrderDraw = true; 385 opState->mTransformFromCompositingAncestor.load(localTransformFromProjectionSurface); 386 compositedChildrenOfProjectionSurface->add(opState); 387 } else { 388 // standard in order draw 389 opState->mSkipInOrderDraw = false; 390 } 391 392 if (mDisplayListData->children.size() > 0) { 393 const bool isProjectionReceiver = mDisplayListData->projectionReceiveIndex >= 0; 394 bool haveAppliedPropertiesToProjection = false; 395 for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) { 396 DrawDisplayListOp* childOp = mDisplayListData->children[i]; 397 RenderNode* child = childOp->mDisplayList; 398 399 Vector<DrawDisplayListOp*>* projectionChildren = NULL; 400 const mat4* projectionTransform = NULL; 401 if (isProjectionReceiver && !child->mProjectBackwards) { 402 // if receiving projections, collect projecting descendent 403 404 // Note that if a direct descendent is projecting backwards, we pass it's 405 // grandparent projection collection, since it shouldn't project onto it's 406 // parent, where it will already be drawing. 407 projectionChildren = &mProjectedNodes; 408 projectionTransform = &mat4::identity(); 409 } else { 410 if (!haveAppliedPropertiesToProjection) { 411 applyViewPropertyTransforms(localTransformFromProjectionSurface); 412 haveAppliedPropertiesToProjection = true; 413 } 414 projectionChildren = compositedChildrenOfProjectionSurface; 415 projectionTransform = &localTransformFromProjectionSurface; 416 } 417 child->computeOrderingImpl(childOp, projectionChildren, projectionTransform); 418 } 419 } 420 421} 422 423class DeferOperationHandler { 424public: 425 DeferOperationHandler(DeferStateStruct& deferStruct, int level) 426 : mDeferStruct(deferStruct), mLevel(level) {} 427 inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) { 428 operation->defer(mDeferStruct, saveCount, mLevel, clipToBounds); 429 } 430 inline LinearAllocator& allocator() { return *(mDeferStruct.mAllocator); } 431 432private: 433 DeferStateStruct& mDeferStruct; 434 const int mLevel; 435}; 436 437void RenderNode::defer(DeferStateStruct& deferStruct, const int level) { 438 DeferOperationHandler handler(deferStruct, level); 439 iterate<DeferOperationHandler>(deferStruct.mRenderer, handler, level); 440} 441 442class ReplayOperationHandler { 443public: 444 ReplayOperationHandler(ReplayStateStruct& replayStruct, int level) 445 : mReplayStruct(replayStruct), mLevel(level) {} 446 inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) { 447#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS 448 mReplayStruct.mRenderer.eventMark(operation->name()); 449#endif 450 operation->replay(mReplayStruct, saveCount, mLevel, clipToBounds); 451 } 452 inline LinearAllocator& allocator() { return *(mReplayStruct.mAllocator); } 453 454private: 455 ReplayStateStruct& mReplayStruct; 456 const int mLevel; 457}; 458 459void RenderNode::replay(ReplayStateStruct& replayStruct, const int level) { 460 ReplayOperationHandler handler(replayStruct, level); 461 462 replayStruct.mRenderer.startMark(mName.string()); 463 iterate<ReplayOperationHandler>(replayStruct.mRenderer, handler, level); 464 replayStruct.mRenderer.endMark(); 465 466 DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", level * 2, "", this, mName.string(), 467 replayStruct.mDrawGlStatus); 468} 469 470void RenderNode::buildZSortedChildList(Vector<ZDrawDisplayListOpPair>& zTranslatedNodes) { 471 if (mDisplayListData == NULL || mDisplayListData->children.size() == 0) return; 472 473 for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) { 474 DrawDisplayListOp* childOp = mDisplayListData->children[i]; 475 RenderNode* child = childOp->mDisplayList; 476 float childZ = child->mTranslationZ; 477 478 if (childZ != 0.0f) { 479 zTranslatedNodes.add(ZDrawDisplayListOpPair(childZ, childOp)); 480 childOp->mSkipInOrderDraw = true; 481 } else if (!child->mProjectBackwards) { 482 // regular, in order drawing DisplayList 483 childOp->mSkipInOrderDraw = false; 484 } 485 } 486 487 // Z sort 3d children (stable-ness makes z compare fall back to standard drawing order) 488 std::stable_sort(zTranslatedNodes.begin(), zTranslatedNodes.end()); 489} 490 491#define SHADOW_DELTA 0.1f 492 493template <class T> 494void RenderNode::iterate3dChildren(const Vector<ZDrawDisplayListOpPair>& zTranslatedNodes, 495 ChildrenSelectMode mode, OpenGLRenderer& renderer, T& handler) { 496 const int size = zTranslatedNodes.size(); 497 if (size == 0 498 || (mode == kNegativeZChildren && zTranslatedNodes[0].key > 0.0f) 499 || (mode == kPositiveZChildren && zTranslatedNodes[size - 1].key < 0.0f)) { 500 // no 3d children to draw 501 return; 502 } 503 504 int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); 505 LinearAllocator& alloc = handler.allocator(); 506 ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, mWidth, mHeight, 507 SkRegion::kIntersect_Op); // clip to 3d root bounds 508 handler(clipOp, PROPERTY_SAVECOUNT, mClipToBounds); 509 510 /** 511 * Draw shadows and (potential) casters mostly in order, but allow the shadows of casters 512 * with very similar Z heights to draw together. 513 * 514 * This way, if Views A & B have the same Z height and are both casting shadows, the shadows are 515 * underneath both, and neither's shadow is drawn on top of the other. 516 */ 517 const size_t nonNegativeIndex = findNonNegativeIndex(zTranslatedNodes); 518 size_t drawIndex, shadowIndex, endIndex; 519 if (mode == kNegativeZChildren) { 520 drawIndex = 0; 521 endIndex = nonNegativeIndex; 522 shadowIndex = endIndex; // draw no shadows 523 } else { 524 drawIndex = nonNegativeIndex; 525 endIndex = size; 526 shadowIndex = drawIndex; // potentially draw shadow for each pos Z child 527 } 528 float lastCasterZ = 0.0f; 529 while (shadowIndex < endIndex || drawIndex < endIndex) { 530 if (shadowIndex < endIndex) { 531 DrawDisplayListOp* casterOp = zTranslatedNodes[shadowIndex].value; 532 RenderNode* caster = casterOp->mDisplayList; 533 const float casterZ = zTranslatedNodes[shadowIndex].key; 534 // attempt to render the shadow if the caster about to be drawn is its caster, 535 // OR if its caster's Z value is similar to the previous potential caster 536 if (shadowIndex == drawIndex || casterZ - lastCasterZ < SHADOW_DELTA) { 537 538 if (caster->mCastsShadow && caster->mAlpha > 0.0f) { 539 mat4 shadowMatrixXY(casterOp->mTransformFromParent); 540 caster->applyViewPropertyTransforms(shadowMatrixXY); 541 542 // Z matrix needs actual 3d transformation, so mapped z values will be correct 543 mat4 shadowMatrixZ(casterOp->mTransformFromParent); 544 caster->applyViewPropertyTransforms(shadowMatrixZ, true); 545 546 DisplayListOp* shadowOp = new (alloc) DrawShadowOp( 547 shadowMatrixXY, shadowMatrixZ, 548 caster->mAlpha, &(caster->mOutline), caster->mWidth, caster->mHeight); 549 handler(shadowOp, PROPERTY_SAVECOUNT, mClipToBounds); 550 } 551 552 lastCasterZ = casterZ; // must do this even if current caster not casting a shadow 553 shadowIndex++; 554 continue; 555 } 556 } 557 558 // only the actual child DL draw needs to be in save/restore, 559 // since it modifies the renderer's matrix 560 int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag); 561 562 DrawDisplayListOp* childOp = zTranslatedNodes[drawIndex].value; 563 RenderNode* child = childOp->mDisplayList; 564 565 renderer.concatMatrix(childOp->mTransformFromParent); 566 childOp->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone 567 handler(childOp, renderer.getSaveCount() - 1, mClipToBounds); 568 childOp->mSkipInOrderDraw = true; 569 570 renderer.restoreToCount(restoreTo); 571 drawIndex++; 572 } 573 handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, mClipToBounds); 574} 575 576template <class T> 577void RenderNode::iterateProjectedChildren(OpenGLRenderer& renderer, T& handler, const int level) { 578 int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); 579 LinearAllocator& alloc = handler.allocator(); 580 ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, mWidth, mHeight, 581 SkRegion::kReplace_Op); // clip to projection surface root bounds 582 handler(clipOp, PROPERTY_SAVECOUNT, mClipToBounds); 583 584 for (size_t i = 0; i < mProjectedNodes.size(); i++) { 585 DrawDisplayListOp* childOp = mProjectedNodes[i]; 586 587 // matrix save, concat, and restore can be done safely without allocating operations 588 int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag); 589 renderer.concatMatrix(childOp->mTransformFromCompositingAncestor); 590 childOp->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone 591 handler(childOp, renderer.getSaveCount() - 1, mClipToBounds); 592 childOp->mSkipInOrderDraw = true; 593 renderer.restoreToCount(restoreTo); 594 } 595 handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, mClipToBounds); 596} 597 598/** 599 * This function serves both defer and replay modes, and will organize the displayList's component 600 * operations for a single frame: 601 * 602 * Every 'simple' state operation that affects just the matrix and alpha (or other factors of 603 * DeferredDisplayState) may be issued directly to the renderer, but complex operations (with custom 604 * defer logic) and operations in displayListOps are issued through the 'handler' which handles the 605 * defer vs replay logic, per operation 606 */ 607template <class T> 608void RenderNode::iterate(OpenGLRenderer& renderer, T& handler, const int level) { 609 if (CC_UNLIKELY(mDestroyed)) { // temporary debug logging 610 ALOGW("Error: %s is drawing after destruction", getName()); 611 CRASH(); 612 } 613 if (mDisplayListData->isEmpty() || mAlpha <= 0) { 614 DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, mName.string()); 615 return; 616 } 617 618#if DEBUG_DISPLAY_LIST 619 Rect* clipRect = renderer.getClipRect(); 620 DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.0f, %.0f, %.0f", 621 level * 2, "", this, mName.string(), clipRect->left, clipRect->top, 622 clipRect->right, clipRect->bottom); 623#endif 624 625 LinearAllocator& alloc = handler.allocator(); 626 int restoreTo = renderer.getSaveCount(); 627 handler(new (alloc) SaveOp(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag), 628 PROPERTY_SAVECOUNT, mClipToBounds); 629 630 DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "", 631 SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo); 632 633 setViewProperties<T>(renderer, handler, level + 1); 634 635 bool quickRejected = mClipToBounds && renderer.quickRejectConservative(0, 0, mWidth, mHeight); 636 if (!quickRejected) { 637 Vector<ZDrawDisplayListOpPair> zTranslatedNodes; 638 buildZSortedChildList(zTranslatedNodes); 639 640 // for 3d root, draw children with negative z values 641 iterate3dChildren(zTranslatedNodes, kNegativeZChildren, renderer, handler); 642 643 DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance(); 644 const int saveCountOffset = renderer.getSaveCount() - 1; 645 const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex; 646 for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) { 647 DisplayListOp *op = mDisplayListData->displayListOps[i]; 648 649#if DEBUG_DISPLAY_LIST 650 op->output(level + 1); 651#endif 652 653 logBuffer.writeCommand(level, op->name()); 654 handler(op, saveCountOffset, mClipToBounds); 655 656 if (CC_UNLIKELY(i == projectionReceiveIndex && mProjectedNodes.size() > 0)) { 657 iterateProjectedChildren(renderer, handler, level); 658 } 659 } 660 661 // for 3d root, draw children with positive z values 662 iterate3dChildren(zTranslatedNodes, kPositiveZChildren, renderer, handler); 663 } 664 665 DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo); 666 handler(new (alloc) RestoreToCountOp(restoreTo), 667 PROPERTY_SAVECOUNT, mClipToBounds); 668 renderer.setOverrideLayerAlpha(1.0f); 669} 670 671void DisplayListData::cleanupResources() { 672 Caches& caches = Caches::getInstance(); 673 caches.unregisterFunctors(functorCount); 674 caches.resourceCache.lock(); 675 676 for (size_t i = 0; i < bitmapResources.size(); i++) { 677 caches.resourceCache.decrementRefcountLocked(bitmapResources.itemAt(i)); 678 } 679 680 for (size_t i = 0; i < ownedBitmapResources.size(); i++) { 681 const SkBitmap* bitmap = ownedBitmapResources.itemAt(i); 682 caches.resourceCache.decrementRefcountLocked(bitmap); 683 caches.resourceCache.destructorLocked(bitmap); 684 } 685 686 for (size_t i = 0; i < patchResources.size(); i++) { 687 caches.resourceCache.decrementRefcountLocked(patchResources.itemAt(i)); 688 } 689 690 for (size_t i = 0; i < shaders.size(); i++) { 691 caches.resourceCache.decrementRefcountLocked(shaders.itemAt(i)); 692 caches.resourceCache.destructorLocked(shaders.itemAt(i)); 693 } 694 695 for (size_t i = 0; i < sourcePaths.size(); i++) { 696 caches.resourceCache.decrementRefcountLocked(sourcePaths.itemAt(i)); 697 } 698 699 for (size_t i = 0; i < layers.size(); i++) { 700 caches.resourceCache.decrementRefcountLocked(layers.itemAt(i)); 701 } 702 703 caches.resourceCache.unlock(); 704 705 for (size_t i = 0; i < paints.size(); i++) { 706 delete paints.itemAt(i); 707 } 708 709 for (size_t i = 0; i < regions.size(); i++) { 710 delete regions.itemAt(i); 711 } 712 713 for (size_t i = 0; i < paths.size(); i++) { 714 delete paths.itemAt(i); 715 } 716 717 for (size_t i = 0; i < matrices.size(); i++) { 718 delete matrices.itemAt(i); 719 } 720 721 bitmapResources.clear(); 722 ownedBitmapResources.clear(); 723 patchResources.clear(); 724 shaders.clear(); 725 sourcePaths.clear(); 726 paints.clear(); 727 regions.clear(); 728 paths.clear(); 729 matrices.clear(); 730 layers.clear(); 731} 732 733}; // namespace uirenderer 734}; // namespace android 735