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