1 /* 2 * Copyright (C) 2014 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 "CanvasContext.h" 18 #include <GpuMemoryTracker.h> 19 20 #include "AnimationContext.h" 21 #include "Caches.h" 22 #include "EglManager.h" 23 #include "Frame.h" 24 #include "LayerUpdateQueue.h" 25 #include "OpenGLPipeline.h" 26 #include "Properties.h" 27 #include "RenderThread.h" 28 #include "hwui/Canvas.h" 29 #include "pipeline/skia/SkiaOpenGLPipeline.h" 30 #include "pipeline/skia/SkiaPipeline.h" 31 #include "pipeline/skia/SkiaVulkanPipeline.h" 32 #include "protos/hwui.pb.h" 33 #include "renderstate/RenderState.h" 34 #include "renderstate/Stencil.h" 35 #include "utils/GLUtils.h" 36 #include "utils/TimeUtils.h" 37 #include "../Properties.h" 38 39 #include <cutils/properties.h> 40 #include <google/protobuf/io/zero_copy_stream_impl.h> 41 #include <private/hwui/DrawGlInfo.h> 42 #include <strings.h> 43 44 #include <fcntl.h> 45 #include <sys/stat.h> 46 #include <algorithm> 47 48 #include <cstdlib> 49 #include <functional> 50 51 #define TRIM_MEMORY_COMPLETE 80 52 #define TRIM_MEMORY_UI_HIDDEN 20 53 54 #define ENABLE_RENDERNODE_SERIALIZATION false 55 56 #define LOG_FRAMETIME_MMA 0 57 58 #if LOG_FRAMETIME_MMA 59 static float sBenchMma = 0; 60 static int sFrameCount = 0; 61 static const float NANOS_PER_MILLIS_F = 1000000.0f; 62 #endif 63 64 namespace android { 65 namespace uirenderer { 66 namespace renderthread { 67 68 CanvasContext* CanvasContext::create(RenderThread& thread, bool translucent, 69 RenderNode* rootRenderNode, IContextFactory* contextFactory) { 70 auto renderType = Properties::getRenderPipelineType(); 71 72 switch (renderType) { 73 case RenderPipelineType::OpenGL: 74 return new CanvasContext(thread, translucent, rootRenderNode, contextFactory, 75 std::make_unique<OpenGLPipeline>(thread)); 76 case RenderPipelineType::SkiaGL: 77 return new CanvasContext(thread, translucent, rootRenderNode, contextFactory, 78 std::make_unique<skiapipeline::SkiaOpenGLPipeline>(thread)); 79 case RenderPipelineType::SkiaVulkan: 80 return new CanvasContext(thread, translucent, rootRenderNode, contextFactory, 81 std::make_unique<skiapipeline::SkiaVulkanPipeline>(thread)); 82 default: 83 LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType); 84 break; 85 } 86 return nullptr; 87 } 88 89 void CanvasContext::destroyLayer(RenderNode* node) { 90 auto renderType = Properties::getRenderPipelineType(); 91 switch (renderType) { 92 case RenderPipelineType::OpenGL: 93 OpenGLPipeline::destroyLayer(node); 94 break; 95 case RenderPipelineType::SkiaGL: 96 case RenderPipelineType::SkiaVulkan: 97 skiapipeline::SkiaPipeline::destroyLayer(node); 98 break; 99 default: 100 LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType); 101 break; 102 } 103 } 104 105 void CanvasContext::invokeFunctor(const RenderThread& thread, Functor* functor) { 106 ATRACE_CALL(); 107 auto renderType = Properties::getRenderPipelineType(); 108 switch (renderType) { 109 case RenderPipelineType::OpenGL: 110 OpenGLPipeline::invokeFunctor(thread, functor); 111 break; 112 case RenderPipelineType::SkiaGL: 113 skiapipeline::SkiaOpenGLPipeline::invokeFunctor(thread, functor); 114 break; 115 case RenderPipelineType::SkiaVulkan: 116 skiapipeline::SkiaVulkanPipeline::invokeFunctor(thread, functor); 117 break; 118 default: 119 LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType); 120 break; 121 } 122 } 123 124 void CanvasContext::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) { 125 auto renderType = Properties::getRenderPipelineType(); 126 switch (renderType) { 127 case RenderPipelineType::OpenGL: 128 OpenGLPipeline::prepareToDraw(thread, bitmap); 129 break; 130 case RenderPipelineType::SkiaGL: 131 case RenderPipelineType::SkiaVulkan: 132 skiapipeline::SkiaPipeline::prepareToDraw(thread, bitmap); 133 break; 134 default: 135 LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType); 136 break; 137 } 138 } 139 140 CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode, 141 IContextFactory* contextFactory, 142 std::unique_ptr<IRenderPipeline> renderPipeline) 143 : mRenderThread(thread) 144 , mGenerationID(0) 145 , mOpaque(!translucent) 146 , mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord())) 147 , mJankTracker(&thread.globalProfileData(), thread.mainDisplayInfo()) 148 , mProfiler(mJankTracker.frames()) 149 , mContentDrawBounds(0, 0, 0, 0) 150 , mRenderPipeline(std::move(renderPipeline)) { 151 rootRenderNode->makeRoot(); 152 mRenderNodes.emplace_back(rootRenderNode); 153 mRenderThread.renderState().registerCanvasContext(this); 154 mProfiler.setDensity(mRenderThread.mainDisplayInfo().density); 155 } 156 157 CanvasContext::~CanvasContext() { 158 destroy(); 159 mRenderThread.renderState().unregisterCanvasContext(this); 160 for (auto& node : mRenderNodes) { 161 node->clearRoot(); 162 } 163 mRenderNodes.clear(); 164 } 165 166 void CanvasContext::addRenderNode(RenderNode* node, bool placeFront) { 167 int pos = placeFront ? 0 : static_cast<int>(mRenderNodes.size()); 168 node->makeRoot(); 169 mRenderNodes.emplace(mRenderNodes.begin() + pos, node); 170 } 171 172 void CanvasContext::removeRenderNode(RenderNode* node) { 173 node->clearRoot(); 174 mRenderNodes.erase(std::remove(mRenderNodes.begin(), mRenderNodes.end(), node), 175 mRenderNodes.end()); 176 } 177 178 void CanvasContext::destroy() { 179 stopDrawing(); 180 setSurface(nullptr); 181 freePrefetchedLayers(); 182 destroyHardwareResources(); 183 mAnimationContext->destroy(); 184 } 185 186 void CanvasContext::setSurface(sp<Surface>&& surface) { 187 ATRACE_CALL(); 188 189 mNativeSurface = std::move(surface); 190 191 ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::Srgb; 192 bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode); 193 194 mFrameNumber = -1; 195 196 if (hasSurface) { 197 mHaveNewSurface = true; 198 mSwapHistory.clear(); 199 } else { 200 mRenderThread.removeFrameCallback(this); 201 mGenerationID++; 202 } 203 } 204 205 void CanvasContext::setSwapBehavior(SwapBehavior swapBehavior) { 206 mSwapBehavior = swapBehavior; 207 } 208 209 bool CanvasContext::pauseSurface() { 210 mGenerationID++; 211 return mRenderThread.removeFrameCallback(this); 212 } 213 214 void CanvasContext::setStopped(bool stopped) { 215 if (mStopped != stopped) { 216 mStopped = stopped; 217 if (mStopped) { 218 mGenerationID++; 219 mRenderThread.removeFrameCallback(this); 220 mRenderPipeline->onStop(); 221 } else if (mIsDirty && hasSurface()) { 222 mRenderThread.postFrameCallback(this); 223 } 224 } 225 } 226 227 void CanvasContext::setup(float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) { 228 mLightGeometry.radius = lightRadius; 229 mLightInfo.ambientShadowAlpha = ambientShadowAlpha; 230 mLightInfo.spotShadowAlpha = spotShadowAlpha; 231 } 232 233 void CanvasContext::setLightCenter(const Vector3& lightCenter) { 234 mLightGeometry.center = lightCenter; 235 } 236 237 void CanvasContext::setOpaque(bool opaque) { 238 mOpaque = opaque; 239 } 240 241 void CanvasContext::setWideGamut(bool wideGamut) { 242 mWideColorGamut = wideGamut; 243 } 244 245 bool CanvasContext::makeCurrent() { 246 if (mStopped) return false; 247 248 auto result = mRenderPipeline->makeCurrent(); 249 switch (result) { 250 case MakeCurrentResult::AlreadyCurrent: 251 return true; 252 case MakeCurrentResult::Failed: 253 mHaveNewSurface = true; 254 setSurface(nullptr); 255 return false; 256 case MakeCurrentResult::Succeeded: 257 mHaveNewSurface = true; 258 return true; 259 default: 260 LOG_ALWAYS_FATAL("unexpected result %d from IRenderPipeline::makeCurrent", 261 (int32_t)result); 262 } 263 264 return true; 265 } 266 267 static bool wasSkipped(FrameInfo* info) { 268 return info && ((*info)[FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame); 269 } 270 271 bool CanvasContext::isSwapChainStuffed() { 272 static const auto SLOW_THRESHOLD = 6_ms; 273 274 if (mSwapHistory.size() != mSwapHistory.capacity()) { 275 // We want at least 3 frames of history before attempting to 276 // guess if the queue is stuffed 277 return false; 278 } 279 nsecs_t frameInterval = mRenderThread.timeLord().frameIntervalNanos(); 280 auto& swapA = mSwapHistory[0]; 281 282 // Was there a happy queue & dequeue time? If so, don't 283 // consider it stuffed 284 if (swapA.dequeueDuration < SLOW_THRESHOLD && swapA.queueDuration < SLOW_THRESHOLD) { 285 return false; 286 } 287 288 for (size_t i = 1; i < mSwapHistory.size(); i++) { 289 auto& swapB = mSwapHistory[i]; 290 291 // If there's a multi-frameInterval gap we effectively already dropped a frame, 292 // so consider the queue healthy. 293 if (swapA.swapCompletedTime - swapB.swapCompletedTime > frameInterval * 3) { 294 return false; 295 } 296 297 // Was there a happy queue & dequeue time? If so, don't 298 // consider it stuffed 299 if (swapB.dequeueDuration < SLOW_THRESHOLD && swapB.queueDuration < SLOW_THRESHOLD) { 300 return false; 301 } 302 303 swapA = swapB; 304 } 305 306 // All signs point to a stuffed swap chain 307 ATRACE_NAME("swap chain stuffed"); 308 return true; 309 } 310 311 void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued, 312 RenderNode* target) { 313 mRenderThread.removeFrameCallback(this); 314 315 // If the previous frame was dropped we don't need to hold onto it, so 316 // just keep using the previous frame's structure instead 317 if (!wasSkipped(mCurrentFrameInfo)) { 318 mCurrentFrameInfo = mJankTracker.startFrame(); 319 } 320 mCurrentFrameInfo->importUiThreadInfo(uiFrameInfo); 321 mCurrentFrameInfo->set(FrameInfoIndex::SyncQueued) = syncQueued; 322 mCurrentFrameInfo->markSyncStart(); 323 324 info.damageAccumulator = &mDamageAccumulator; 325 info.layerUpdateQueue = &mLayerUpdateQueue; 326 327 mAnimationContext->startFrame(info.mode); 328 mRenderPipeline->onPrepareTree(); 329 for (const sp<RenderNode>& node : mRenderNodes) { 330 // Only the primary target node will be drawn full - all other nodes would get drawn in 331 // real time mode. In case of a window, the primary node is the window content and the other 332 // node(s) are non client / filler nodes. 333 info.mode = (node.get() == target ? TreeInfo::MODE_FULL : TreeInfo::MODE_RT_ONLY); 334 node->prepareTree(info); 335 GL_CHECKPOINT(MODERATE); 336 } 337 mAnimationContext->runRemainingAnimations(info); 338 GL_CHECKPOINT(MODERATE); 339 340 freePrefetchedLayers(); 341 GL_CHECKPOINT(MODERATE); 342 343 mIsDirty = true; 344 345 if (CC_UNLIKELY(!mNativeSurface.get())) { 346 mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame); 347 info.out.canDrawThisFrame = false; 348 return; 349 } 350 351 if (CC_LIKELY(mSwapHistory.size() && !Properties::forceDrawFrame)) { 352 nsecs_t latestVsync = mRenderThread.timeLord().latestVsync(); 353 SwapHistory& lastSwap = mSwapHistory.back(); 354 nsecs_t vsyncDelta = std::abs(lastSwap.vsyncTime - latestVsync); 355 // The slight fudge-factor is to deal with cases where 356 // the vsync was estimated due to being slow handling the signal. 357 // See the logic in TimeLord#computeFrameTimeNanos or in 358 // Choreographer.java for details on when this happens 359 if (vsyncDelta < 2_ms) { 360 // Already drew for this vsync pulse, UI draw request missed 361 // the deadline for RT animations 362 info.out.canDrawThisFrame = false; 363 } 364 /* This logic exists to try and recover from a display latch miss, which essentially 365 * results in the bufferqueue being double-buffered instead of triple-buffered. 366 * SurfaceFlinger itself now tries to handle & recover from this situation, so this 367 * logic should no longer be necessary. As it's occasionally triggering when 368 * undesired disable it. 369 * TODO: Remove this entirely if the results are solid. 370 else if (vsyncDelta >= mRenderThread.timeLord().frameIntervalNanos() * 3 || 371 (latestVsync - mLastDropVsync) < 500_ms) { 372 // It's been several frame intervals, assume the buffer queue is fine 373 // or the last drop was too recent 374 info.out.canDrawThisFrame = true; 375 } else { 376 info.out.canDrawThisFrame = !isSwapChainStuffed(); 377 if (!info.out.canDrawThisFrame) { 378 // dropping frame 379 mLastDropVsync = mRenderThread.timeLord().latestVsync(); 380 } 381 } 382 */ 383 } else { 384 info.out.canDrawThisFrame = true; 385 } 386 387 // TODO: Do we need to abort out if the backdrop is added but not ready? Should that even 388 // be an allowable combination? 389 if (mRenderNodes.size() > 2 && !mRenderNodes[1]->isRenderable()) { 390 info.out.canDrawThisFrame = false; 391 } 392 393 if (!info.out.canDrawThisFrame) { 394 mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame); 395 } 396 397 bool postedFrameCallback = false; 398 if (info.out.hasAnimations || !info.out.canDrawThisFrame) { 399 if (CC_UNLIKELY(!Properties::enableRTAnimations)) { 400 info.out.requiresUiRedraw = true; 401 } 402 if (!info.out.requiresUiRedraw) { 403 // If animationsNeedsRedraw is set don't bother posting for an RT anim 404 // as we will just end up fighting the UI thread. 405 mRenderThread.postFrameCallback(this); 406 postedFrameCallback = true; 407 } 408 } 409 410 if (!postedFrameCallback && 411 info.out.animatedImageDelay != TreeInfo::Out::kNoAnimatedImageDelay) { 412 // Subtract the time of one frame so it can be displayed on time. 413 const nsecs_t kFrameTime = mRenderThread.timeLord().frameIntervalNanos(); 414 if (info.out.animatedImageDelay <= kFrameTime) { 415 mRenderThread.postFrameCallback(this); 416 } else { 417 const auto delay = info.out.animatedImageDelay - kFrameTime; 418 int genId = mGenerationID; 419 mRenderThread.queue().postDelayed(delay, [this, genId]() { 420 if (mGenerationID == genId) { 421 mRenderThread.postFrameCallback(this); 422 } 423 }); 424 } 425 } 426 } 427 428 void CanvasContext::stopDrawing() { 429 mRenderThread.removeFrameCallback(this); 430 mAnimationContext->pauseAnimators(); 431 mGenerationID++; 432 } 433 434 void CanvasContext::notifyFramePending() { 435 ATRACE_CALL(); 436 mRenderThread.pushBackFrameCallback(this); 437 } 438 439 void CanvasContext::draw() { 440 SkRect dirty; 441 mDamageAccumulator.finish(&dirty); 442 443 // TODO: Re-enable after figuring out cause of b/22592975 444 // if (dirty.isEmpty() && Properties::skipEmptyFrames) { 445 // mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame); 446 // return; 447 // } 448 449 mCurrentFrameInfo->markIssueDrawCommandsStart(); 450 451 Frame frame = mRenderPipeline->getFrame(); 452 453 SkRect windowDirty = computeDirtyRect(frame, &dirty); 454 455 bool drew = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry, &mLayerUpdateQueue, 456 mContentDrawBounds, mOpaque, mWideColorGamut, mLightInfo, 457 mRenderNodes, &(profiler())); 458 459 int64_t frameCompleteNr = mFrameCompleteCallbacks.size() ? getFrameNumber() : -1; 460 461 waitOnFences(); 462 463 bool requireSwap = false; 464 bool didSwap = 465 mRenderPipeline->swapBuffers(frame, drew, windowDirty, mCurrentFrameInfo, &requireSwap); 466 467 mIsDirty = false; 468 469 if (requireSwap) { 470 if (!didSwap) { // some error happened 471 setSurface(nullptr); 472 } 473 SwapHistory& swap = mSwapHistory.next(); 474 swap.damage = windowDirty; 475 swap.swapCompletedTime = systemTime(CLOCK_MONOTONIC); 476 swap.vsyncTime = mRenderThread.timeLord().latestVsync(); 477 if (mNativeSurface.get()) { 478 int durationUs; 479 nsecs_t dequeueStart = mNativeSurface->getLastDequeueStartTime(); 480 if (dequeueStart < mCurrentFrameInfo->get(FrameInfoIndex::SyncStart)) { 481 // Ignoring dequeue duration as it happened prior to frame render start 482 // and thus is not part of the frame. 483 swap.dequeueDuration = 0; 484 } else { 485 mNativeSurface->query(NATIVE_WINDOW_LAST_DEQUEUE_DURATION, &durationUs); 486 swap.dequeueDuration = us2ns(durationUs); 487 } 488 mNativeSurface->query(NATIVE_WINDOW_LAST_QUEUE_DURATION, &durationUs); 489 swap.queueDuration = us2ns(durationUs); 490 } else { 491 swap.dequeueDuration = 0; 492 swap.queueDuration = 0; 493 } 494 mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration) = swap.dequeueDuration; 495 mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration) = swap.queueDuration; 496 mHaveNewSurface = false; 497 mFrameNumber = -1; 498 } else { 499 mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration) = 0; 500 mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration) = 0; 501 } 502 503 // TODO: Use a fence for real completion? 504 mCurrentFrameInfo->markFrameCompleted(); 505 506 #if LOG_FRAMETIME_MMA 507 float thisFrame = mCurrentFrameInfo->duration(FrameInfoIndex::IssueDrawCommandsStart, 508 FrameInfoIndex::FrameCompleted) / 509 NANOS_PER_MILLIS_F; 510 if (sFrameCount) { 511 sBenchMma = ((9 * sBenchMma) + thisFrame) / 10; 512 } else { 513 sBenchMma = thisFrame; 514 } 515 if (++sFrameCount == 10) { 516 sFrameCount = 1; 517 ALOGD("Average frame time: %.4f", sBenchMma); 518 } 519 #endif 520 521 if (didSwap) { 522 for (auto& func : mFrameCompleteCallbacks) { 523 std::invoke(func, frameCompleteNr); 524 } 525 mFrameCompleteCallbacks.clear(); 526 } 527 528 mJankTracker.finishFrame(*mCurrentFrameInfo); 529 if (CC_UNLIKELY(mFrameMetricsReporter.get() != nullptr)) { 530 mFrameMetricsReporter->reportFrameMetrics(mCurrentFrameInfo->data()); 531 } 532 533 GpuMemoryTracker::onFrameCompleted(); 534 #ifdef BUGREPORT_FONT_CACHE_USAGE 535 auto renderType = Properties::getRenderPipelineType(); 536 if (RenderPipelineType::OpenGL == renderType) { 537 Caches& caches = Caches::getInstance(); 538 caches.fontRenderer.getFontRenderer().historyTracker().frameCompleted(); 539 } 540 #endif 541 } 542 543 // Called by choreographer to do an RT-driven animation 544 void CanvasContext::doFrame() { 545 if (!mRenderPipeline->isSurfaceReady()) return; 546 prepareAndDraw(nullptr); 547 } 548 549 void CanvasContext::prepareAndDraw(RenderNode* node) { 550 ATRACE_CALL(); 551 552 nsecs_t vsync = mRenderThread.timeLord().computeFrameTimeNanos(); 553 int64_t frameInfo[UI_THREAD_FRAME_INFO_SIZE]; 554 UiFrameInfoBuilder(frameInfo).addFlag(FrameInfoFlags::RTAnimation).setVsync(vsync, vsync); 555 556 TreeInfo info(TreeInfo::MODE_RT_ONLY, *this); 557 prepareTree(info, frameInfo, systemTime(CLOCK_MONOTONIC), node); 558 if (info.out.canDrawThisFrame) { 559 draw(); 560 } else { 561 // wait on fences so tasks don't overlap next frame 562 waitOnFences(); 563 } 564 } 565 566 void CanvasContext::markLayerInUse(RenderNode* node) { 567 if (mPrefetchedLayers.erase(node)) { 568 node->decStrong(nullptr); 569 } 570 } 571 572 void CanvasContext::freePrefetchedLayers() { 573 if (mPrefetchedLayers.size()) { 574 for (auto& node : mPrefetchedLayers) { 575 ALOGW("Incorrectly called buildLayer on View: %s, destroying layer...", 576 node->getName()); 577 node->destroyLayers(); 578 node->decStrong(nullptr); 579 } 580 mPrefetchedLayers.clear(); 581 } 582 } 583 584 void CanvasContext::buildLayer(RenderNode* node) { 585 ATRACE_CALL(); 586 if (!mRenderPipeline->isContextReady()) return; 587 588 // buildLayer() will leave the tree in an unknown state, so we must stop drawing 589 stopDrawing(); 590 591 TreeInfo info(TreeInfo::MODE_FULL, *this); 592 info.damageAccumulator = &mDamageAccumulator; 593 info.layerUpdateQueue = &mLayerUpdateQueue; 594 info.runAnimations = false; 595 node->prepareTree(info); 596 SkRect ignore; 597 mDamageAccumulator.finish(&ignore); 598 // Tickle the GENERIC property on node to mark it as dirty for damaging 599 // purposes when the frame is actually drawn 600 node->setPropertyFieldsDirty(RenderNode::GENERIC); 601 602 mRenderPipeline->renderLayers(mLightGeometry, &mLayerUpdateQueue, mOpaque, mWideColorGamut, 603 mLightInfo); 604 605 node->incStrong(nullptr); 606 mPrefetchedLayers.insert(node); 607 } 608 609 bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) { 610 return mRenderPipeline->copyLayerInto(layer, bitmap); 611 } 612 613 void CanvasContext::destroyHardwareResources() { 614 stopDrawing(); 615 if (mRenderPipeline->isContextReady()) { 616 freePrefetchedLayers(); 617 for (const sp<RenderNode>& node : mRenderNodes) { 618 node->destroyHardwareResources(); 619 } 620 mRenderPipeline->onDestroyHardwareResources(); 621 } 622 } 623 624 void CanvasContext::trimMemory(RenderThread& thread, int level) { 625 auto renderType = Properties::getRenderPipelineType(); 626 switch (renderType) { 627 case RenderPipelineType::OpenGL: { 628 // No context means nothing to free 629 if (!thread.eglManager().hasEglContext()) return; 630 ATRACE_CALL(); 631 if (level >= TRIM_MEMORY_COMPLETE) { 632 thread.renderState().flush(Caches::FlushMode::Full); 633 thread.eglManager().destroy(); 634 } else if (level >= TRIM_MEMORY_UI_HIDDEN) { 635 thread.renderState().flush(Caches::FlushMode::Moderate); 636 } 637 break; 638 } 639 case RenderPipelineType::SkiaGL: 640 case RenderPipelineType::SkiaVulkan: { 641 // No context means nothing to free 642 if (!thread.getGrContext()) return; 643 ATRACE_CALL(); 644 if (level >= TRIM_MEMORY_COMPLETE) { 645 thread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::Complete); 646 thread.eglManager().destroy(); 647 thread.vulkanManager().destroy(); 648 } else if (level >= TRIM_MEMORY_UI_HIDDEN) { 649 thread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::UiHidden); 650 } 651 break; 652 } 653 default: 654 LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType); 655 break; 656 } 657 } 658 659 DeferredLayerUpdater* CanvasContext::createTextureLayer() { 660 return mRenderPipeline->createTextureLayer(); 661 } 662 663 void CanvasContext::dumpFrames(int fd) { 664 mJankTracker.dumpStats(fd); 665 mJankTracker.dumpFrames(fd); 666 } 667 668 void CanvasContext::resetFrameStats() { 669 mJankTracker.reset(); 670 } 671 672 void CanvasContext::setName(const std::string&& name) { 673 mJankTracker.setDescription(JankTrackerType::Window, std::move(name)); 674 } 675 676 void CanvasContext::serializeDisplayListTree() { 677 #if ENABLE_RENDERNODE_SERIALIZATION 678 using namespace google::protobuf::io; 679 char package[128]; 680 // Check whether tracing is enabled for this process. 681 FILE* file = fopen("/proc/self/cmdline", "r"); 682 if (file) { 683 if (!fgets(package, 128, file)) { 684 ALOGE("Error reading cmdline: %s (%d)", strerror(errno), errno); 685 fclose(file); 686 return; 687 } 688 fclose(file); 689 } else { 690 ALOGE("Error opening /proc/self/cmdline: %s (%d)", strerror(errno), errno); 691 return; 692 } 693 char path[1024]; 694 snprintf(path, 1024, "/data/data/%s/cache/rendertree_dump", package); 695 int fd = open(path, O_CREAT | O_WRONLY, S_IRWXU | S_IRGRP | S_IROTH); 696 if (fd == -1) { 697 ALOGD("Failed to open '%s'", path); 698 return; 699 } 700 proto::RenderNode tree; 701 // TODO: Streaming writes? 702 mRootRenderNode->copyTo(&tree); 703 std::string data = tree.SerializeAsString(); 704 write(fd, data.c_str(), data.length()); 705 close(fd); 706 #endif 707 } 708 709 void CanvasContext::waitOnFences() { 710 if (mFrameFences.size()) { 711 ATRACE_CALL(); 712 for (auto& fence : mFrameFences) { 713 fence->getResult(); 714 } 715 mFrameFences.clear(); 716 } 717 } 718 719 class CanvasContext::FuncTaskProcessor : public TaskProcessor<bool> { 720 public: 721 explicit FuncTaskProcessor(TaskManager* taskManager) : TaskProcessor<bool>(taskManager) {} 722 723 virtual void onProcess(const sp<Task<bool> >& task) override { 724 FuncTask* t = static_cast<FuncTask*>(task.get()); 725 t->func(); 726 task->setResult(true); 727 } 728 }; 729 730 void CanvasContext::enqueueFrameWork(std::function<void()>&& func) { 731 if (!mFrameWorkProcessor.get()) { 732 mFrameWorkProcessor = new FuncTaskProcessor(mRenderPipeline->getTaskManager()); 733 } 734 sp<FuncTask> task(new FuncTask()); 735 task->func = func; 736 mFrameFences.push_back(task); 737 mFrameWorkProcessor->add(task); 738 } 739 740 int64_t CanvasContext::getFrameNumber() { 741 // mFrameNumber is reset to -1 when the surface changes or we swap buffers 742 if (mFrameNumber == -1 && mNativeSurface.get()) { 743 mFrameNumber = static_cast<int64_t>(mNativeSurface->getNextFrameNumber()); 744 } 745 return mFrameNumber; 746 } 747 748 SkRect CanvasContext::computeDirtyRect(const Frame& frame, SkRect* dirty) { 749 if (frame.width() != mLastFrameWidth || frame.height() != mLastFrameHeight) { 750 // can't rely on prior content of window if viewport size changes 751 dirty->setEmpty(); 752 mLastFrameWidth = frame.width(); 753 mLastFrameHeight = frame.height(); 754 } else if (mHaveNewSurface || frame.bufferAge() == 0) { 755 // New surface needs a full draw 756 dirty->setEmpty(); 757 } else { 758 if (!dirty->isEmpty() && !dirty->intersect(0, 0, frame.width(), frame.height())) { 759 ALOGW("Dirty " RECT_STRING " doesn't intersect with 0 0 %d %d ?", SK_RECT_ARGS(*dirty), 760 frame.width(), frame.height()); 761 dirty->setEmpty(); 762 } 763 profiler().unionDirty(dirty); 764 } 765 766 if (dirty->isEmpty()) { 767 dirty->set(0, 0, frame.width(), frame.height()); 768 } 769 770 // At this point dirty is the area of the window to update. However, 771 // the area of the frame we need to repaint is potentially different, so 772 // stash the screen area for later 773 SkRect windowDirty(*dirty); 774 775 // If the buffer age is 0 we do a full-screen repaint (handled above) 776 // If the buffer age is 1 the buffer contents are the same as they were 777 // last frame so there's nothing to union() against 778 // Therefore we only care about the > 1 case. 779 if (frame.bufferAge() > 1) { 780 if (frame.bufferAge() > (int)mSwapHistory.size()) { 781 // We don't have enough history to handle this old of a buffer 782 // Just do a full-draw 783 dirty->set(0, 0, frame.width(), frame.height()); 784 } else { 785 // At this point we haven't yet added the latest frame 786 // to the damage history (happens below) 787 // So we need to damage 788 for (int i = mSwapHistory.size() - 1; 789 i > ((int)mSwapHistory.size()) - frame.bufferAge(); i--) { 790 dirty->join(mSwapHistory[i].damage); 791 } 792 } 793 } 794 795 return windowDirty; 796 } 797 798 } /* namespace renderthread */ 799 } /* namespace uirenderer */ 800 } /* namespace android */ 801