DisplayList.cpp revision 39a908c1df89e1073627b0dcbce922d826b67055
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#include <SkCanvas.h> 18 19#include "Debug.h" 20#include "DisplayList.h" 21#include "DisplayListOp.h" 22#include "DisplayListLogBuffer.h" 23 24namespace android { 25namespace uirenderer { 26 27void DisplayList::outputLogBuffer(int fd) { 28 DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance(); 29 if (logBuffer.isEmpty()) { 30 return; 31 } 32 33 FILE *file = fdopen(fd, "a"); 34 35 fprintf(file, "\nRecent DisplayList operations\n"); 36 logBuffer.outputCommands(file); 37 38 String8 cachesLog; 39 Caches::getInstance().dumpMemoryUsage(cachesLog); 40 fprintf(file, "\nCaches:\n%s", cachesLog.string()); 41 fprintf(file, "\n"); 42 43 fflush(file); 44} 45 46DisplayList::DisplayList(const DisplayListRenderer& recorder) : 47 mDestroyed(false), mTransformMatrix(NULL), mTransformCamera(NULL), mTransformMatrix3D(NULL), 48 mStaticMatrix(NULL), mAnimationMatrix(NULL) { 49 50 initFromDisplayListRenderer(recorder); 51} 52 53DisplayList::~DisplayList() { 54 mDestroyed = true; 55 clearResources(); 56} 57 58void DisplayList::destroyDisplayListDeferred(DisplayList* displayList) { 59 if (displayList) { 60 DISPLAY_LIST_LOGD("Deferring display list destruction"); 61 Caches::getInstance().deleteDisplayListDeferred(displayList); 62 } 63} 64 65void DisplayList::clearResources() { 66 mDisplayListData = NULL; 67 68 mClipRectOp = NULL; 69 mSaveLayerOp = NULL; 70 mSaveOp = NULL; 71 mRestoreToCountOp = 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 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 < 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 mFilterResources.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 // allocate reusable ops for state-deferral 167 LinearAllocator& alloc = mDisplayListData->allocator; 168 mClipRectOp = new (alloc) ClipRectOp(); 169 mSaveLayerOp = new (alloc) SaveLayerOp(); 170 mSaveOp = new (alloc) SaveOp(); 171 mRestoreToCountOp = new (alloc) RestoreToCountOp(); 172 if (CC_UNLIKELY(!mSaveOp)) { // temporary debug logging 173 ALOGW("Error: %s's SaveOp not allocated, size %d", getName(), mSize); 174 CRASH(); 175 } 176 177 mFunctorCount = recorder.getFunctorCount(); 178 179 Caches& caches = Caches::getInstance(); 180 caches.registerFunctors(mFunctorCount); 181 caches.resourceCache.lock(); 182 183 const Vector<SkBitmap*>& bitmapResources = recorder.getBitmapResources(); 184 for (size_t i = 0; i < bitmapResources.size(); i++) { 185 SkBitmap* resource = bitmapResources.itemAt(i); 186 mBitmapResources.add(resource); 187 caches.resourceCache.incrementRefcountLocked(resource); 188 } 189 190 const Vector<SkBitmap*> &ownedBitmapResources = recorder.getOwnedBitmapResources(); 191 for (size_t i = 0; i < ownedBitmapResources.size(); i++) { 192 SkBitmap* resource = ownedBitmapResources.itemAt(i); 193 mOwnedBitmapResources.add(resource); 194 caches.resourceCache.incrementRefcountLocked(resource); 195 } 196 197 const Vector<SkiaColorFilter*>& filterResources = recorder.getFilterResources(); 198 for (size_t i = 0; i < filterResources.size(); i++) { 199 SkiaColorFilter* resource = filterResources.itemAt(i); 200 mFilterResources.add(resource); 201 caches.resourceCache.incrementRefcountLocked(resource); 202 } 203 204 const Vector<SkiaShader*>& shaders = recorder.getShaders(); 205 for (size_t i = 0; i < shaders.size(); i++) { 206 SkiaShader* resource = shaders.itemAt(i); 207 mShaders.add(resource); 208 caches.resourceCache.incrementRefcountLocked(resource); 209 } 210 211 const SortedVector<SkPath*>& sourcePaths = recorder.getSourcePaths(); 212 for (size_t i = 0; i < sourcePaths.size(); i++) { 213 mSourcePaths.add(sourcePaths.itemAt(i)); 214 caches.resourceCache.incrementRefcountLocked(sourcePaths.itemAt(i)); 215 } 216 217 const Vector<Layer*>& layers = recorder.getLayers(); 218 for (size_t i = 0; i < layers.size(); i++) { 219 mLayers.add(layers.itemAt(i)); 220 caches.resourceCache.incrementRefcountLocked(layers.itemAt(i)); 221 } 222 223 caches.resourceCache.unlock(); 224 225 mPaints.appendVector(recorder.getPaints()); 226 mRegions.appendVector(recorder.getRegions()); 227 mPaths.appendVector(recorder.getPaths()); 228 mMatrices.appendVector(recorder.getMatrices()); 229} 230 231void DisplayList::init() { 232 mSize = 0; 233 mIsRenderable = true; 234 mFunctorCount = 0; 235 mLeft = 0; 236 mTop = 0; 237 mRight = 0; 238 mBottom = 0; 239 mClipToBounds = true; 240 mAlpha = 1; 241 mHasOverlappingRendering = true; 242 mTranslationX = 0; 243 mTranslationY = 0; 244 mRotation = 0; 245 mRotationX = 0; 246 mRotationY= 0; 247 mScaleX = 1; 248 mScaleY = 1; 249 mPivotX = 0; 250 mPivotY = 0; 251 mCameraDistance = 0; 252 mMatrixDirty = false; 253 mMatrixFlags = 0; 254 mPrevWidth = -1; 255 mPrevHeight = -1; 256 mWidth = 0; 257 mHeight = 0; 258 mPivotExplicitlySet = false; 259 mCaching = false; 260} 261 262size_t DisplayList::getSize() { 263 return mSize; 264} 265 266/** 267 * This function is a simplified version of replay(), where we simply retrieve and log the 268 * display list. This function should remain in sync with the replay() function. 269 */ 270void DisplayList::output(uint32_t level) { 271 ALOGD("%*sStart display list (%p, %s, render=%d)", (level - 1) * 2, "", this, 272 mName.string(), isRenderable()); 273 ALOGD("%*s%s %d", level * 2, "", "Save", 274 SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); 275 276 outputViewProperties(level); 277 int flags = DisplayListOp::kOpLogFlag_Recurse; 278 for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) { 279 mDisplayListData->displayListOps[i]->output(level, flags); 280 } 281 282 ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, mName.string()); 283} 284 285float DisplayList::getPivotX() { 286 updateMatrix(); 287 return mPivotX; 288} 289 290float DisplayList::getPivotY() { 291 updateMatrix(); 292 return mPivotY; 293} 294 295void DisplayList::updateMatrix() { 296 if (mMatrixDirty) { 297 if (!mTransformMatrix) { 298 mTransformMatrix = new SkMatrix(); 299 } 300 if (mMatrixFlags == 0 || mMatrixFlags == TRANSLATION) { 301 mTransformMatrix->reset(); 302 } else { 303 if (!mPivotExplicitlySet) { 304 if (mWidth != mPrevWidth || mHeight != mPrevHeight) { 305 mPrevWidth = mWidth; 306 mPrevHeight = mHeight; 307 mPivotX = mPrevWidth / 2.0f; 308 mPivotY = mPrevHeight / 2.0f; 309 } 310 } 311 if ((mMatrixFlags & ROTATION_3D) == 0) { 312 mTransformMatrix->setTranslate(mTranslationX, mTranslationY); 313 mTransformMatrix->preRotate(mRotation, mPivotX, mPivotY); 314 mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY); 315 } else { 316 if (!mTransformCamera) { 317 mTransformCamera = new Sk3DView(); 318 mTransformMatrix3D = new SkMatrix(); 319 } 320 mTransformMatrix->reset(); 321 mTransformCamera->save(); 322 mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY); 323 mTransformCamera->rotateX(mRotationX); 324 mTransformCamera->rotateY(mRotationY); 325 mTransformCamera->rotateZ(-mRotation); 326 mTransformCamera->getMatrix(mTransformMatrix3D); 327 mTransformMatrix3D->preTranslate(-mPivotX, -mPivotY); 328 mTransformMatrix3D->postTranslate(mPivotX + mTranslationX, 329 mPivotY + mTranslationY); 330 mTransformMatrix->postConcat(*mTransformMatrix3D); 331 mTransformCamera->restore(); 332 } 333 } 334 mMatrixDirty = false; 335 } 336} 337 338void DisplayList::outputViewProperties(const int level) { 339 updateMatrix(); 340 if (mLeft != 0 || mTop != 0) { 341 ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", mLeft, mTop); 342 } 343 if (mStaticMatrix) { 344 ALOGD("%*sConcatMatrix (static) %p: " MATRIX_STRING, 345 level * 2, "", mStaticMatrix, MATRIX_ARGS(mStaticMatrix)); 346 } 347 if (mAnimationMatrix) { 348 ALOGD("%*sConcatMatrix (animation) %p: " MATRIX_STRING, 349 level * 2, "", mAnimationMatrix, MATRIX_ARGS(mStaticMatrix)); 350 } 351 if (mMatrixFlags != 0) { 352 if (mMatrixFlags == TRANSLATION) { 353 ALOGD("%*sTranslate %f, %f", level * 2, "", mTranslationX, mTranslationY); 354 } else { 355 ALOGD("%*sConcatMatrix %p: " MATRIX_STRING, 356 level * 2, "", mTransformMatrix, MATRIX_ARGS(mTransformMatrix)); 357 } 358 } 359 360 bool clipToBoundsNeeded = mClipToBounds; 361 if (mAlpha < 1) { 362 if (mCaching) { 363 ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mAlpha); 364 clipToBoundsNeeded = false; // clipping done by layer 365 } else if (!mHasOverlappingRendering) { 366 ALOGD("%*sScaleAlpha %.2f", level * 2, "", mAlpha); 367 } else { 368 int flags = SkCanvas::kHasAlphaLayer_SaveFlag; 369 if (clipToBoundsNeeded) { 370 flags |= SkCanvas::kClipToLayer_SaveFlag; 371 clipToBoundsNeeded = false; // clipping done by save layer 372 } 373 ALOGD("%*sSaveLayerAlpha %.2f, %.2f, %.2f, %.2f, %d, 0x%x", level * 2, "", 374 (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop, 375 (int)(mAlpha * 255), flags); 376 } 377 } 378 if (clipToBoundsNeeded) { 379 ALOGD("%*sClipRect %.2f, %.2f, %.2f, %.2f", level * 2, "", 0.0f, 0.0f, 380 (float) mRight - mLeft, (float) mBottom - mTop); 381 } 382} 383 384/* 385 * For property operations, we pass a savecount of 0, since the operations aren't part of the 386 * displaylist, and thus don't have to compensate for the record-time/playback-time discrepancy in 387 * base saveCount (i.e., how RestoreToCount uses saveCount + mCount) 388 */ 389#define PROPERTY_SAVECOUNT 0 390 391template <class T> 392void DisplayList::setViewProperties(OpenGLRenderer& renderer, T& handler, 393 const int level) { 394#if DEBUG_DISPLAY_LIST 395 outputViewProperties(level); 396#endif 397 updateMatrix(); 398 if (mLeft != 0 || mTop != 0) { 399 renderer.translate(mLeft, mTop); 400 } 401 if (mStaticMatrix) { 402 renderer.concatMatrix(mStaticMatrix); 403 } else if (mAnimationMatrix) { 404 renderer.concatMatrix(mAnimationMatrix); 405 } 406 if (mMatrixFlags != 0) { 407 if (mMatrixFlags == TRANSLATION) { 408 renderer.translate(mTranslationX, mTranslationY); 409 } else { 410 renderer.concatMatrix(mTransformMatrix); 411 } 412 } 413 bool clipToBoundsNeeded = mClipToBounds; 414 if (mAlpha < 1) { 415 if (mCaching) { 416 renderer.setOverrideLayerAlpha(mAlpha); 417 clipToBoundsNeeded = false; // clipping done by layer 418 } else if (!mHasOverlappingRendering) { 419 renderer.scaleAlpha(mAlpha); 420 } else { 421 // TODO: should be able to store the size of a DL at record time and not 422 // have to pass it into this call. In fact, this information might be in the 423 // location/size info that we store with the new native transform data. 424 int saveFlags = SkCanvas::kHasAlphaLayer_SaveFlag; 425 if (clipToBoundsNeeded) { 426 saveFlags |= SkCanvas::kClipToLayer_SaveFlag; 427 clipToBoundsNeeded = false; // clipping done by saveLayer 428 } 429 handler(mSaveLayerOp->reinit(0, 0, mRight - mLeft, mBottom - mTop, 430 mAlpha * 255, SkXfermode::kSrcOver_Mode, saveFlags), PROPERTY_SAVECOUNT, 431 mClipToBounds); 432 } 433 } 434 if (clipToBoundsNeeded) { 435 handler(mClipRectOp->reinit(0, 0, mRight - mLeft, mBottom - mTop, SkRegion::kIntersect_Op), 436 PROPERTY_SAVECOUNT, mClipToBounds); 437 } 438} 439 440class DeferOperationHandler { 441public: 442 DeferOperationHandler(DeferStateStruct& deferStruct, int level) 443 : mDeferStruct(deferStruct), mLevel(level) {} 444 inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) { 445 operation->defer(mDeferStruct, saveCount, mLevel, clipToBounds); 446 } 447private: 448 DeferStateStruct& mDeferStruct; 449 const int mLevel; 450}; 451 452void DisplayList::defer(DeferStateStruct& deferStruct, const int level) { 453 DeferOperationHandler handler(deferStruct, level); 454 iterate<DeferOperationHandler>(deferStruct.mRenderer, handler, level); 455} 456 457class ReplayOperationHandler { 458public: 459 ReplayOperationHandler(ReplayStateStruct& replayStruct, int level) 460 : mReplayStruct(replayStruct), mLevel(level) {} 461 inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) { 462#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS 463 mReplayStruct.mRenderer.eventMark(operation->name()); 464#endif 465 operation->replay(mReplayStruct, saveCount, mLevel, clipToBounds); 466 } 467private: 468 ReplayStateStruct& mReplayStruct; 469 const int mLevel; 470}; 471 472void DisplayList::replay(ReplayStateStruct& replayStruct, const int level) { 473 ReplayOperationHandler handler(replayStruct, level); 474 475 replayStruct.mRenderer.startMark(mName.string()); 476 iterate<ReplayOperationHandler>(replayStruct.mRenderer, handler, level); 477 replayStruct.mRenderer.endMark(); 478 479 DISPLAY_LIST_LOGD("%*sDone (%p, %s), returning %d", level * 2, "", this, mName.string(), 480 replayStruct.mDrawGlStatus); 481} 482 483/** 484 * This function serves both defer and replay modes, and will organize the displayList's component 485 * operations for a single frame: 486 * 487 * Every 'simple' operation that affects just the matrix and alpha (or other factors of 488 * DeferredDisplayState) may be issued directly to the renderer, but complex operations (with custom 489 * defer logic) and operations in displayListOps are issued through the 'handler' which handles the 490 * defer vs replay logic, per operation 491 */ 492template <class T> 493void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level) { 494 if (CC_UNLIKELY(mDestroyed)) { // temporary debug logging 495 ALOGW("Error: %s is drawing after destruction, size %d", getName(), mSize); 496 CRASH(); 497 } 498 if (mSize == 0 || mAlpha <= 0) { 499 DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, mName.string()); 500 return; 501 } 502 503#if DEBUG_DISPLAY_LIST 504 Rect* clipRect = renderer.getClipRect(); 505 DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), clipRect: %.0f, %.0f, %.0f, %.0f", 506 level * 2, "", this, mName.string(), clipRect->left, clipRect->top, 507 clipRect->right, clipRect->bottom); 508#endif 509 510 int restoreTo = renderer.getSaveCount(); 511 handler(mSaveOp->reinit(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag), 512 PROPERTY_SAVECOUNT, mClipToBounds); 513 514 DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "", 515 SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo); 516 517 setViewProperties<T>(renderer, handler, level + 1); 518 519 if (mClipToBounds && renderer.quickRejectNoScissor(0, 0, mWidth, mHeight)) { 520 DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo); 521 handler(mRestoreToCountOp->reinit(restoreTo), PROPERTY_SAVECOUNT, mClipToBounds); 522 renderer.restoreToCount(restoreTo); 523 renderer.setOverrideLayerAlpha(1.0f); 524 return; 525 } 526 527 DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance(); 528 int saveCount = renderer.getSaveCount() - 1; 529 for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) { 530 DisplayListOp *op = mDisplayListData->displayListOps[i]; 531 532#if DEBUG_DISPLAY_LIST 533 op->output(level + 1); 534#endif 535 536 logBuffer.writeCommand(level, op->name()); 537 handler(op, saveCount, mClipToBounds); 538 } 539 540 DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo); 541 handler(mRestoreToCountOp->reinit(restoreTo), PROPERTY_SAVECOUNT, mClipToBounds); 542 renderer.restoreToCount(restoreTo); 543 renderer.setOverrideLayerAlpha(1.0f); 544} 545 546}; // namespace uirenderer 547}; // namespace android 548