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