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