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